Spring之AOP(基於註解)
目標類
public class MathCalculator {
public int div(int i,int j){
return i/j;
}
}
切面類
@Aspect public class LogAspects { //抽取公共的切入點表示式 //1、本類引用 //2、其他的切面引用 @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))") public void pointCut(){}; //@Before在目標方法之前切入;切入點表示式(指定在哪個方法切入) @Before("pointCut()") public void logStart(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); System.out.println(joinPoint.getSignature().getName()+"執行。。。@Before:引數列表是:{"+Arrays.asList(args)+"}"); } @After("com.atguigu.aop.LogAspects.pointCut()") public void logEnd(JoinPoint joinPoint){ System.out.println(joinPoint.getSignature().getName()+"結束。。。@After"); } //JoinPoint一定要出現在引數表的第一位 @AfterReturning(value="pointCut()",returning="result") public void logReturn(JoinPoint joinPoint,Object result){ System.out.println(joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:執行結果:{"+result+"}"); } @AfterThrowing(value="pointCut()",throwing="exception") public void logException(JoinPoint joinPoint,Exception exception){ System.out.println(joinPoint.getSignature().getName()+"異常。。。異常資訊:{"+exception+"}"); } }
配置類
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
//業務邏輯類加入容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}
//切面類加入到容器中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
AOP:【動態代理】
指在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式
-
匯入aop模組,Spring AOP:(spring-aspects)
-
定義一個業務邏輯類(MathCalculator),在業務邏輯執行的時候將日誌進行列印(方法之前、方法執行結束、方法出現異常,xxx)
-
定義一個日誌切面類(LogAspects):切面類裡面的方法需要動態感知MathCalculator.div執行到哪裡然後執行
通知方法: 前置通知(@Before):logStart:在目標方法(div)執行之前執行 後置通知(@After):logEnd:在目標方法(div)執行結束之後執行(無論方法正常結束還是異常結束) 返回通知(@AfterReturning):logReturn:在目標方法(div)正常返回之後執行 異常通知(@AfterThrowing):logException:在目標方法(div)出現異常以後執行 環繞通知(@Around):動態代理,手動推進目標方法執行(joinPoint.procced())
-
給切面類的目標方法標註何時何地執行(通知註解)
-
將切面類和業務邏輯類(目標方法所在類)都加入到容器中;將切面類和業務邏輯類(目標方法所在類)都加入到容器中
-
必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)
-
給配置類中加 @EnableAspectJAutoProxy 【開啟基於註解的aop模式】給配置類中加 @EnableAspectJAutoProxy 【開啟基於註解的aop模式】
在Spring中很多的 @EnableXXX
三步曲:
1)、將業務邏輯元件和切面類都加入到容器中,告訴Spring哪個是切面類(@Aspect)
2)、在切面類上的每一個通知方法上標註通知註解,告訴Spring何時何地執行(切入點表示式)
3)、開啟基於註解的aop模式,@EnableAspectJAutoProxy
AOP原理:【看給容器中註冊了什麼元件,這個元件什麼時候工作,這個元件的功能是什麼?】
1、@EnableAspectJAutoProxy是什麼?
@Import(AspectJAutoProxyRegistrar.class):給容器中匯入AspectJAutoProxyRegistrar
利用AspectJAutoProxyRegistrar自定義給容器中註冊bean:BeanDefinetion
internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
給容器中註冊一個AnnotationAwareAspectJAutoProxyCreator
2、 AnnotationAwareAspectJAutoProxyCreator:
AnnotationAwareAspectJAutoProxyCreator
->AspectJAwareAdvisorAutoProxyCreator
->AbstractAdvisorAutoProxyCreator
->AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
關注後置處理器(在bean初始化完成前後做事情)、自動裝配BeanFactory
流程:
1)、傳入配置類,建立ioc容器
2)、註冊配置類,呼叫refresh()重新整理容器
3)、registerBeanPostProcessors(beanFactory);註冊bean的後置處理器來方便攔截bean的建立
1)、先獲取ioc容器已經定義了的需要建立物件的所有BeanPostProcessor
2)、給容器中加別的BeanPostProcessor
3)、優先註冊實現了PriorityOrdered介面的BeanPostProcessor
4)、再給容器中註冊實現了Ordered介面的BeanPostProcessor
5)、註冊沒實現優先順序介面的BeanPostProcessor
6)、註冊BeanPostProcessor,實際上就是建立BeanPostProcessor物件,儲存在容器中
建立internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
1)、建立Bean的例項
2)、populateBean:給bean的各種屬性賦值
3)、initializeBean:初始化bean;
1)、invokeAwareMethods():處理Aware介面的方法回撥
2)、applyBeanPostProcessorsBeforeInitialization():應用後置處理器的postProcessBeforeInitialization()
3)、invokeInitMethods():執行自定義的初始化方法
4)、applyBeanPostProcessorsAfterInitialization():執行後置處理器的postProcessAfterInitialization();
4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)建立成功----》aspectJAdvisorsBuilder
7)、把BeanPostProcessor註冊到BeanFactory中:
beanFactory.addBeanPostProcessor(postProcessor);
總結:
1)、@EnableAspectJAutoProxy 開啟AOP功能
2)、@EnableAspectJAutoProxy 會給容器中註冊一個元件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一個後置處理器;
4)、容器的建立流程:
1)、registerBeanPostProcessors()註冊後置處理器,建立AnnotationAwareAspectJAutoProxyCreator物件
2)、finishBeanFactoryInitialization()初始化剩下的單例項bean
1)、建立業務邏輯元件和切面元件
2)、AnnotationAwareAspectJAutoProxyCreator攔截元件的建立過程
3)、元件建立完之後,判斷元件是否需要增強
是:切面的通知方法,包裝成增強器(Advisor);給業務邏輯元件建立一個代理物件(cglib);
5)、執行目標方法:
1)、代理物件執行目標方法
2)、CglibAopProxy.intercept();
1)、得到目標方法的攔截器鏈(增強器包裝成攔截器MethodInterceptor)
2)、利用攔截器的鏈式機制,依次進入每一個攔截器進行執行;
3)、效果:
正常執行:前置通知-》目標方法-》後置通知-》返回通知
出現異常:前置通知-》目標方法-》後置通知-》異常通知