SpringAOP 全自動編程
1、什麼是AOP
AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
AOP採取橫向抽取機制,取代了傳統縱向繼承體系重複性代碼。Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期通過代理方式向目標類織入增強代碼。
2、什麼是AspectJ
AspectJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入。
3、AOP實現原理
1、aop底層將採用代理機制進行實現。
2、接口 + 實現類 :spring採用 jdk的動態代理Proxy。
3、實現類:spring 採用 cglib字節碼增強。
4、AOP術語
1.target:目標類,需要被代理的類。例如:UserService
2.Joinpoint(連接點):所謂連接點是指那些可能被攔截到的方法。例如:所有的方法
3.PointCut 切入點:已經被增強的連接點。例如:addUser()
4.advice 通知/增強,增強代碼。例如:after、before
5. Weaving(織入):是指把增強advice應用到目標對象target來創建新的代理對象proxy的過程.
6.proxy 代理類
7.Aspect(切面): 是切入點pointcut和通知advice的結合。 一個線是一個特殊的面。 一個切入點和一個通知,組成成一個特殊的面。
5、CGLIB字節碼增強
沒有接口,只有實現類。採用字節碼增強框架 cglib,在運行時創建目標類的子類,從而對目標類進行增強。
6、AOP聯盟通知類型
Spring按照通知Advice在目標類方法的連接點位置,可以分爲5類
1、前置通知 org.springframework.aop.MethodBeforeAdvice:在目標方法執行前實施增強
2、後置通知 org.springframework.aop.AfterReturningAdvice:在目標方法執行後實施增強
3、環繞通知 org.aopalliance.intercept.MethodInterceptor:在目標方法執行前後實施增強。必須手動執行目標方法。
4、異常拋出通知 org.springframework.aop.ThrowsAdvice:在方法拋出異常後實施增強
5、引介通知 org.springframework.aop.IntroductionInterceptor:在目標類中添加一些新的方法和屬性【略】
【注意】環繞通知的格式爲:
try{
//前置通知【前置通知可以阻止執行目標方法】
//執行目標方法
//後置通知【後置通知可以獲得目標方法的返回值】
} catch(){
//拋出異常通知
}
7、Spring AOP 全自動編程
原理:從Spring容器獲得目標類,如果配置AOP,Spring將自動生成代理。
步驟:
1、導入Jar包:
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-3.2.0.RELEASE.jar
2、編寫接口 interface UserService
public interface UserService {
public void add();
public void update();
public void delete();
}
3、編寫接口的實現類 UserServiceImpl
public class UserServiceImpl implements UserService {
/* (non-Javadoc)
* @see com.Lily.SpringLearning.g_SpringAOP.UserService#add()
*/
@Override
public void add() {
// TODO Auto-generated method stub
System.out.println("AOP Add() " +this.getClass().toString());
}
/* (non-Javadoc)
* @see com.Lily.SpringLearning.g_SpringAOP.UserService#update()
*/
@Override
public void update() {
// TODO Auto-generated method stub
System.out.println("AOP Update() "+this.getClass().toString());
}
/* (non-Javadoc)
* @see com.Lily.SpringLearning.g_SpringAOP.UserService#delete()
*/
@Override
public void delete() {
// TODO Auto-generated method stub
System.out.println("AOP Delete() "+this.getClass().toString());
}
}
4、編寫切面類 LilyAspect
【這裏要確定通知的類型,實現對應的接口】這裏注意,採用的是環繞通知的方法,所以要實現MethodInterceptor,這個接口在兩個Jar包都有,添加的時候注意是org.aopalliance.intercept.MethodInterceptor 這個。
還有invoke方法中要記得手動執行目標方法:
//手動執行目標方法
Objectobj=arg0.proceed();
/**
*
*/
package com.Lily.SpringLearning.g_SpringAOP;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* *
* @author LilyLee
* @date 2017年6月22日
* @time 上午9:50:29
* @Version 1.0
* @email [email protected]
*
*/
public class LilyAspect implements MethodInterceptor {
/* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// TODO Auto-generated method stub
System.out.println("環繞通知——前方法 ");
//手動執行目標方法
Object obj=arg0.proceed();
System.out.println("環繞通知——後方法 ");
return obj;
}
}
5、配置xml
頭部新增:
xmlns:aop=http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
編寫內容
1、創建目標類
<beanid="?" class="?"></bean>
2、創建切面類
<beanid="?(Aspect)" class="?"></bean>
3、AOP編程【導入命名空間、config配置、切入點表達式】
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.Lily_spring_aop.*.*(..))"id="myPointCut"/>
<aop:advisor advice-ref="AspectId" pointcut-ref="myPointCut"/>
</aop:config>
*這裏 true是聲明使用CGLIB代理
*切入點表達式 execution(* com.itheima.c_spring_aop.*.*(..))
execution( | * | com.Lily.Spring | .* | .* | (..)) |
選擇方法 | 返回值任意 | 包名 | 類名任意 | 方法名任意 | 參數任意 |
<aop:advisor>特殊的切面,只有一個通知 和 一個切入點
advice-ref 通知引用
pointcut-ref 切入點引用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userServiceId" class="com.Lily.SpringLearning.g_SpringAOP.UserServiceImpl"></bean>
<bean id="LilyAspectId" class="com.Lily.SpringLearning.g_SpringAOP.LilyAspect"></bean>
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.Lily.SpringLearning.g_SpringAOP.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="LilyAspectId" pointcut-ref="myPointCut"/>
</aop:config>
</beans>
6、編寫測試類
public class Test {
@org.junit.Test
public void test() {
String xmlPath = "com/Lily/SpringLearning/g_SpringAOP/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//獲得目標類
UserService u = (UserService) applicationContext.getBean("userServiceId");
u.add();
u.delete();
u.update();
}
}
報錯:
org.springframework.beans.factory.NoSuchBeanDefinitionException:No bean named 'userServiceId' is defined
atorg.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:549)
atorg.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1096)
atorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
atorg.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
atorg.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117)
atcom.Lily.SpringLearning.g_SpringAOP.Test.test(Test.java:28)
atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
atjava.lang.reflect.Method.invoke(Method.java:606)
atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
atorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)
atorg.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
atorg.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
在bean的配置裏面寫錯了“userSerciveId”
Spring出錯,90%都是配置文件的鍋啊!!