淺嘗Spring註解開發_AOP原理及完整過程分析(源碼)
淺嘗Spring註解開發_AOP原理及完整過程分析(源碼)
淺嘗Spring註解開發,基於Spring 4.3.12
分析AOP執行過程及源碼,包含AOP註解使用、AOP原理、分析AnnotationAwareAspectJAutoProxyCreator、AOP代理、攔截器、鏈式調用
以初學者的角度跟著雷豐陽的影片走完AOP整個過程,設計很巧妙。補充了自己的理解,為了流程連續性,所以全放在放在一篇里,如有錯誤請多多指教。
淺嘗Spring註解開發_自定義註冊組件、屬性賦值、自動裝配
淺嘗Spring註解開發_Bean生命周期及執行過程
淺嘗Spring註解開發_AOP原理及完整過程分析(源碼)
AOP註解使用
AOP動態代理:指在程式運行期間動態的將某段程式碼切入到指定方法指定位置進行運行的編程方式
1)、將業務邏輯組件和切面類都加入到容器中,告訴Spring哪個是切面類(@Aspect)
2)、在切面類上的每一個通知方法上標註通知註解,告訴Spring何時何地運行(切入點表達式)
3)、開啟基於註解的aop模式:@EnableAspectJAutoProxy
1、導入aop模組;Spring AOP:(spring-aspects)
2、定義一個業務邏輯類(MathCalculator);在業務邏輯運行的時候將日誌進行列印(方法之前、方法運行結束、方法出現異常,xxx)
3、定義一個日誌切面類(LogAspects):切面類裡面的方法需要動態感知MathCalculator.div運行到哪裡然後執行;
通知方法:
前置通知(@Before):logStart:在目標方法(div())運行之前運行
後置通知(@After):logEnd:在目標方法(div())運行結束之後運行(無論方法正常結束還是異常結束)
返回通知(@AfterReturning):logReturn:在目標方法(div())正常返回之後運行
異常通知(@AfterThrowing):logException:在目標方法(div())出現異常以後運行
環繞通知(@Around):動態代理,手動推進目標方法運行(joinPoint.procced())
4、給切面類的目標方法標註何時何地運行(通知註解);
5、將切面類和業務邏輯類(目標方法所在類)都加入到容器中;
6、必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)
[7]、給配置類中加 @EnableAspectJAutoProxy 【開啟基於註解的aop模式】
在Spring中很多的 @EnableXXX;
-
導入aop模組:org.springframework.spring-aspects
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.12.RELEASE</version> </dependency> -
定義一個業務邏輯類(MathCalculator)。在業務邏輯運行的時候將日誌進行列印(方法之前、方法運行結束、方法出現異常,xxx)。
//業務類 public class MathCalculator { public int div(int i,int j){ System.out.println("MathCalculator...div..."); return i/j; } } -
定義一個日誌切面類(LogAspects):切面類裡面的方法需要動態感知MathCalculator.div運行到哪裡然後執行。通知方法:
- 前置通知(@Before):logStart:在目標方法(div)運行之前運行
- 最終通知(@After):logEnd:在目標方法(div)運行結束之後運行(無論方法正常結束還是異常結束)
- 後置通知/返回通知(@AfterReturning):logReturn:在目標方法(div)正常返回之後運行
- 異常通知(@AfterThrowing):logException:在目標方法(div)出現異常以後運行
- 環繞通知(@Around):動態代理,手動推進目標方法運行(joinPoint.proceed())
-
給切面類的目標方法標註何時何地運行(通知註解)。
//@Aspect: 告訴Spring當前類是一個切面類 @Aspect public class LogAspects { //抽取公共的切入點表達式,空方法,只使用註解 //1、本類引用使用:pointCut() //2、其他的切面引用使用:com.xxx.aop.LogAspects.pointCut() @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))") public void pointCut(){}; //前置通知,JoinPoint可以獲取切入點資訊 //@Before在目標方法之前切入,切入點表達式(指定在哪個方法切入),JoinPoint封裝了切面方法資訊 @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+"}"); } } -
將切面類和業務邏輯類(目標方法所在類)都加入到容器中。
-
必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)。
-
給配置類中加 @EnableAspectJAutoProxy (開啟基於註解的aop模式)
- 在Spring中很多的 @EnableXXX
//開啟基於註解的aop模式 @EnableAspectJAutoProxy @Configuration public class MainConfigOfAOP { //業務邏輯類加入容器中 @Bean public MathCalculator calculator(){ return new MathCalculator(); } //切面類加入到容器中 @Bean public LogAspects logAspects(){ return new LogAspects(); } } -
測試
-
必須使用Spring容器調用
public class IOCTest_AOP { @Test public void test01(){ AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class); //1、不要自己創建對象 // MathCalculator mathCalculator = new MathCalculator(); // mathCalculator.div(1, 1); MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.div(1, 0); applicationContext.close(); } } -
輸出
div運行...@Before:參數列表是{[1,0]} //業務方法運行 MathCalculator...div... div結束...@After div異常...異常資訊:{java.lang.ArithmeticException: / by zero}
-
⭐AOP原理
看給容器中註冊了什麼組件,這個組件什麼時候工作,這個組件的功能是什麼?
- 先將AnnotationAwareAspectJAutoProxyCreator(注釋感知AspectJ自動代理創建器)注入容器
0. AnnotationAwareAspectJAutoProxyCreator[BeanPostProcessor]本身也是Bean,Bean注入的過程如下:- InstantiationAwareBeanPostProcessor實例化後置處理器
- 創建Bean實例
- InstantiationAwareBeanPostProcessor實例化後置處理器
- Bean屬性賦值
- 初始化Bean
0. 每一個[自定義等]初始化都要執行,過程如下:- 處理Aware介面的方法回調
- BeanPostProcessor初始化後置處理器前置方法
- [自定義]初始化
- BeanPostProcessor初始化後置處理器後置方法
⭐開始時幹了啥?@EnableAspectJAutoProxy註解
@EnableAspectJAutoProxy最終給容器中註冊一個AnnotationAwareAspectJAutoProxyCreator(註解裝配模式的AspectJ切面自動代理創建器)
- 進入@EnableAspectJAutoProxy
- 發現註解@Import(AspectJAutoProxyRegistrar.class)給容器中導入AspectJAutoProxyRegistrar組件
- 它實現了ImportBeanDefinitionRegistart,這是一個介面,可以實現自定義註冊組件(在之前的注入組件文章中講過)
- 它給容器自定義註冊bean定義資訊(BeanDefinetion) ,就是org.springframework.aop.config.internalAutoProxyCreator,類型是AnnotationAwareAspectJAutoProxyCreator(註解裝配模式的AspectJ切面自動代理創建器)
- 並且判斷@EnableAspectJAutoProxy註解並處理資訊
AnnotationAwareAspectJAutoProxyCreator繼承關係
AnnotationAwareAspectJAutoProxyCreator
-> extends AspectJAwareAdvisorAutoProxyCreator
-> extends AbstractAdvisorAutoProxyCreator
-> extends AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(關注後置處理器(在bean初始化完成前後做事情)、自動裝配BeanFactory)
⭐大有來頭?分析AnnotationAwareAspectJAutoProxyCreator
查看AnnotationAwareAspectJAutoProxyCreator繼承關係中這些類的方法,找出與後置處理器和Bean工廠有關的方法,打斷點觀察,包括上面注入的ioc入口、業務和AOP。從父類開始:
注意區別兩個不同的後置處理器
postProcessBeforeInstantiation 實例化前的後處理(這個是[Smart]InstantiationAwareBeanPostProcessor的)
postProcessBeforeInitialization 初始化前的後處理(這個是BeanPostProcessor的)
- AbstractAutoProxyCreator(抽象自動代理創建者)
- AbstractAutoProxyCreator.setBeanFactory()
- AbstractAutoProxyCreator.有後置處理器的邏輯(postProcessBeforeInstantiation(實例化前的後置處理器))
- AbstractAdvisorAutoProxyCreator.[重寫]setBeanFactory()-->{ initBeanFactory() }
- 給AbstractAdvisorAutoProxyCreator.setBeanFactory()打上斷點
- AnnotationAwareAspectJAutoProxyCreator.[重寫]initBeanFactory()
⭐我註冊我?註冊AnnotationAwareAspectJAutoProxyCreator
「我」(指BeanPostProcessor)註冊「我」(指AnnotationAwareAspectJAutoProxyCreator),這裡是說AnnotationAwareAspectJAutoProxyCreator本質是BeanPostProcessor,它自己要按照BeanPostProcessor的方式註冊
通過後置處理器注入了一個後置處理器
執行過程
啟動程式,首先創建容器
-
AnnotationConfigApplicationContext傳入配置類,創建ioc容器 -
註冊配置類
register(),調用refresh()刷新容器 -
refresh()中有registerBeanPostProcessors(beanFactory)註冊bean的後置處理器(注釋:註冊攔截 Bean 創建的 Bean 處理器),用來攔截bean的創建 -
後置處理器的註冊邏輯:
-
beanFactory.getBeanNamesForType()先獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor(為什麼更啟動就有已定義的BeanPostProcessor?是因為在啟動時有一個註解@EnableAspectJAutoProxy已經註冊了一個AnnotationAwareAspectJAutoProxyCreator和容器中其他一些默認的,只是定義還沒創建對象,在上面講過)- 根據獲取的
postProcessorNames,發現裡面有一個org.springframework.aop.config.internalAutoProxyCreator,就是通過@EnableAspectJAutoProxy註冊的AnnotationAwareAspectJAutoProxyCreator類型的屬性的名字 - 接下來按照
postProcessorNames來創建對象 beanFactory.addBeanPostProcessor()給容器中加入別的BeanPostProcessor- 通過
postProcessorNames判斷是否有實現Ordered優先順序介面的,分別放在一起分步處理- 優先註冊實現了
PriorityOrdered介面的BeanPostProcessor - 再給容器中註冊實現了
Ordered介面的BeanPostProcessor - 註冊沒實現優先順序介面的
BeanPostProcessor - 執行每個優先順序中的
beanFactory.getBean(ppName, BeanPostProcessor.class),跳轉到下一調用創建Bean
- 優先註冊實現了
- 註冊
BeanPostProcessor,實際上就是創建BeanPostProcessor對象,保存在容器中(重要,每次創建Bean都要執行,BeanPostProcessor本質也是Bean)
0. 下面創建internalAutoProxyCreator的BeanPostProcessor類型是AnnotationAwareAspectJAutoProxyCreator- 創建Bean的實例(先從
beanFactory.getBean()獲取名字,由getBean()->doGetBean(),在doGetBean()中調getSingleton()獲取單實例的bean,第一次沒有,所以用singletonFactory.getObject()->createBean()->doCreateBean()->createBeanInstance()創建bean實例,下面進行初始化。如同之前講過的BeanPostProcessor原理) populateBean(beanName,mbd,instanceWrapper):給bean的各種屬性賦值initializeBean(beanName,exposedObject,mbd):初始化beaninvokeAwareMethods(beanName,bean):處理Aware介面的方法回調- 先判斷是否是
BeanFactoryAware類型,然後到達AbstractAutoProxyCreator.setBeanFactory(beanFactory)方法,就是上面分析AnnotationAwareAspectJAutoProxyCreator的父類AbstractAutoProxyCreator。 - 然後執行
initBeanFactory(beanFactory)初始化BeanFacotry
- 先判斷是否是
applyBeanPostProcessorsBeforeInitialization():應用後置處理器的postProcessBeforeInitialization()invokeInitMethods(beanName,wrappedBean,mbd):執行自定義的初始化方法applyBeanPostProcessorsAfterInitialization():執行後置處理器的postProcessAfterInitialization()
BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創建成功
- 創建Bean的實例(先從
- 把
BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)註冊到BeanFactory中,beanFactory.addBeanPostProcessor(postProcessor)給BeanFactory添加新的BeanPostProcessor。
以上是創建和註冊AnnotationAwareAspectJAutoProxyCreator的過程
- 根據獲取的
部分源碼
-
註冊後置處理器
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // 註冊記錄資訊消息的BeanPostProcessorChecker // bean是在BeanPostProcessor實例化期間創建的 // bean不適合被所有BeanPostProcessors處理。 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // 在實現prioritordered、Ordered和其他功能的BeanPostProcessors之間分離。 List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>(); List<String> orderedPostProcessorNames = new ArrayList<String>(); List<String> nonOrderedPostProcessorNames = new ArrayList<String>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // 首先,註冊實現prioritordered的BeanPostProcessors。 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 接下來,註冊實現Ordered的BeanPostProcessors。 List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>(); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); // 現在,註冊所有常規的BeanPostProcessors。 List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>(); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 最後,重新註冊所有內部BeanPostProcessors。 sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // 將用於檢測內部bean的後處理器重新註冊為applicationlistener, // 將它移動到處理器鏈的末端(用於獲取代理等)。 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); } -
屬性賦值與初始化
// 初始化bean實例 Object exposedObject = bean; try { // 屬性賦值 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } -
初始化BeanFacotry
public void setBeanFactory(BeanFactory beanFactory) { super.setBeanFactory(beanFactory); if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory); } else { //初始化BeanFacotry this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory); } }
運行時棧資訊
-
beanFactory.getBeanNamesForType()先獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor
-
創建bean

-
把
BeanPostProcessor註冊到BeanFactory中,給BeanFactory添加BeanPostProcessor
⭐你比我快?AnnotationAwareAspectJAutoProxyCreator執行時機
「你」(指AnnotationAwareAspectJAutoProxyCreator)比「我」(指BeanPostProcessor)快,這裡是說AnnotationAwareAspectJAutoProxyCreator早於某些BeanPostProcessor執行,可以提前實例化一些組件
上面程式碼執行後,註冊了AnnotationAwareAspectJAutoProxyCreator,它是一個後置處理器,當其他組件在創建對象時,都要經過創建Bean實例、給Bean屬性賦值、初始化及前後處理器,所以它可以攔截到這些組件的創建過程,接下來要看它作為後置處理器都做了什麼?
執行流程
接著上面的AbstractAutoProxyCreator.setBeanFactory(beanFactory)執行,然後調用AbstractAutoProxyCreator.postProcessBeforeInstantiation(),注意區分[Smart]InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()和BeanPostProcessor.postProcessBeforeInitialization(),這一點上面分析AnnotationAwareAspectJAutoProxyCreator時也有提到,為什麼會調用這個方法?在整個程式開始時,AnnotationConfigApplicationContext創建ioc容器註冊配置,register()調用refresh()刷新容器,上面第(3)步執行的是registerBeanPostProcessors(beanFactory)註冊bean的後置處理器方法,在它下面有一個finishBeanFactoryInitialization(beanFactory)方法
-
finishBeanFactoryInitialization(beanFactory):完成BeanFactory初始化工作,創建剩下的單實例bean-
遍歷獲取容器中所有的Bean,依次創建對象(這一步還沒創建,只是獲取,下一步才創建)
DefaultListableBeanFactory.getBean(beanName)->AbstractBeanFactory.getBean()->doGetBean()->getSingleton(beanName, new ObjectFactory<Object>())=>創建Bean實例,返回一個sharedInstance屬性,注釋是"Create bean instance"(創建bean實例)- 觀察之前的程式碼,發現sharedInstance已經創建
Object sharedInstance = getSingleton(beanName)注釋是"Eagerly check singleton cache for manually registered singletons(急切地檢查單例快取中是否有手動註冊的單例)" - 可以發現Bean不是直接創建出來的
-
創建bean
-
先從快取中獲取當前bean,如果能獲取到,說明bean是之前被創建過的,直接使用,否則再創建。只要創建好的Bean都會被快取起來
-
執行
getSingleton(beanName, new ObjectFactory<Object>())參數中的匿名內部類方法 -
createBean():創建bean-
createBean()創建bean包括RootBeanDefinition mbd是bean的定義資訊等,繼續執行 -
resolveBeforeInstantiation(beanName, mbdToUse)注釋是"Give BeanPostProcessors a chance to return a proxy instead of the target bean instance"(讓BeanPostProcessors有機會返回一個代理而不是目標bean實例)-
解析
BeforeInstantiation,希望後置處理器在此能返回一個代理對象 -
如果能返回代理對象就使用,如果不能就繼續,後置處理器先嘗試返回對象:
- 分析:
AnnotationAwareAspectJAutoProxyCreator會在任何bean創建之前先嘗試返回bean的實例InstantiationAwareBeanPostProcessor是在創建Bean實例之前先嘗試用後置處理器返回對象的BeanPostProcessor是在Bean對象創建完成[自定義]初始化前後調用的- 【
InstantiationAwareBeanPostProcessor是在構造方法前後執行(就在這一步),BeanPostProcessor是在Bean屬性賦值[初始化之後],自定義初始化前後執行(就在下一步)】
//拿到所有後置處理器,如果是InstantiationAwareBeanPostProcessor就執行postProcessBeforeInstantiation bean = applyBeanPostProcessorsBeforeInstantiation(): if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } //------------ if (bp instanceof InstantiationAwareBeanPostProcessor) { ibp.postProcessBeforeInstantiation(beanClass, beanName); }
-
-
doCreateBean(beanName, mbdToUse, args):真正的去創建一個bean實例,包括createBeanInstance()創建Bean實例、populateBean()屬性賦值、initializeBean()初始化Bean、Aware介面、前置後置等,和上一節的(3.4)一樣
-
-
-
部分源碼
-
創建一個 Bean 實例
/** * 此類的中心方法:創建一個 Bean 實例, * 填充 Bean 實例、應用後處理器等。 * @see #doCreateBean */ @Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // 確保此時實際解析了 Bean 類,並且 // 在動態解析類的情況下克隆 Bean 定義 // 不能存儲在共享的合併 Bean 定義中。 Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // 準備方法覆蓋。 try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // 給 BeanPostProcessors 一個返回代理而不是目標 Bean 實例的機會。 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } // 實際創建指定的bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } -
嘗試返回一個代理
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // 確保此時實際解析了 Bean 類。 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
運行時棧資訊
-
準備實例化

⭐你先我後?創建AOP代理
「你」(指AnnotationAwareAspectJAutoProxyCreator[類型是InstantiationAwareBeanPostProcessor])先「我」(指其他某些BeanPostProcessor)後
經過上面的流程,已經知道創建Bean需要調用AnnotationAwareAspectJAutoProxyCreator[類型是InstantiationAwareBeanPostProcessor]的後置處理器,然後才是初始化前後的BeanPostProcessor後置處理器,下面關心在AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation()中都做了什麼操作
執行過程
- 繼續上節倒數第二步,進入應用後置處理器中,每一個bean創建之前,調用
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
0. 關心MathCalculator[業務類]和LogAspect[切面類]的創建this.advisedBeans.contaionsKey(cacheKey)判斷當前bean是否在advisedBeans中(保存了所有需要增強bean)?現在沒有isInfrastructureClass(beanClass)判斷當前bean是否是基礎類型的Advice、Pointcut、Advisor、AopInfrastructureBean,this.aspectJAdvisorFactory.isAspect(beanClass)或者是否是切面(通過有沒有@Aspect註解判斷)shouldSkip(beanClass,beanName)是否需要跳過List<Advisor> candidateAdvisors = findCandidateAdvisors()找到候選的增強器(增強器就是自定義的LogAspect切面中通知方法),每一個封裝的通知方法的增強器是InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.atguigu.aop.LogAspects.logStart(org.aspectj.lang.JoinPoint)],判斷每一個增強器是否是AspectJPointcutAdvisor類型的,是就返回true,現在都不是
- 然後創建bean對象後,(在初始化後)執行
[AbstractAutoProxyCreator]BeanPostProcessor.postProcessAfterInitialization()
0. 進入return wrapIfNecessary(bean, beanName, cacheKey)如有必要,就包裝,只有被代理類才會創建代理對象Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null)注釋是Create proxy if we have advice(如果我們有通知方法,請創建代理)獲取當前bean的所有增強器(通知方法),進入findEligibleAdvisors(beanClass,beanName)找到候選的所有的增強器(找哪些通知方法是需要切入當前bean方法的)- 獲取到能在bean使用的增強器,如切入點表達式
- 給增強器排序
- 已經獲取到可用增強器,保存當前bean在已增強集合中
this.advisedBeans.put() - 如果當前bean需要增強,創建當前bean的代理對象
Object proxy = createProxy()- 獲取所有增強器(通知方法)
- 保存到
proxyFactory - 創建代理對象
proxyFactory.getProxy(getProxyClassLoader()):Spring自動決定兩種方式JdkDynamicAopProxy(config):jdk動態代理(需要介面);ObjenesisCglibAopProxy(config):cglib的動態代理;
- 創建完成後得到的bean的增強代理對象
- 給容器中返回當前組件使用cglib增強了的代理對象
- 以後容器中獲取到的就是這個組件的代理對象
MathCalculator(業務類)$EnhancerBySpringCGLIB,執行目標方法的時候,代理對象就會執行通知方法的流程
部分源碼
-
如果必要包裝
//必要時包裝給定的bean,即,如果它符合被代理的條件。 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //... // 如果我們有建議,請創建代理。 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 保存可用增強器 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 創建代理對象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } -
創建代理
// 創建一個CGLIB代理或JDK動態代理。 @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 判斷是否介面 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { // 創建JDK動態代理 return new JdkDynamicAopProxy(config); } // 創建CGLIB代理 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
⭐如此包裝?獲取攔截器鏈MethodInterceptor
如此「包裝」(將切入點增強器包裝為方法攔截器)
接著上面程式碼執行,在上面已經獲取到被代理後的對象,現在需要把所有的增強方法轉為MethodInterceptor類型。
執行過程
-
(被代理後的)目標方法執行:容器中保存了組件的代理對象(cglib增強後的對象),這個對象裡面保存了詳細資訊(比如增強器,目標對象,xxx)
-
debug 從ioc容器中的目標方法執行開始進入下一步(或者:入-出-出-入-出-入-出-入)
-
CglibAopProxy.intercept():攔截目標方法的執行 -
根據
ProxyFactory對象獲取將要執行的目標方法攔截器鏈:List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)保存所有攔截器,攔截器列表長度就是config.getAdvisors()長度,等於5。包括一個默認的ExposeInvocationInterceptor和 4個(自定義)增強器- 遍歷所有的增強器,如果是切入點的增強器,將其轉為攔截器
MethodInterceptor,MethodInterceptor[] interceptor = registry.getInterceptors(advisor)
3. 將增強器轉為List<MethodInterceptor>攔截器- 如果是
MethodInterceptor,直接加入到集合中 - 如果不是,使用
AdvisorAdapter將增強器轉為MethodInterceptor
3. 轉換完成返回MethodInterceptor數組
- 如果是
-
或者本身是
Interceptor,或者由其他類型轉為MethodInterceptor,最終返回攔截器列表(此次是5個)
-
-
如果沒有攔截器鏈
chain.isEmpty(),直接執行目標方法methodProxy.invoke()- 如果有攔截器鏈,把需要執行的目標對象,目標方法,攔截器鏈等資訊傳入創建一個
CglibMethodInvocation對象,並調用Object retVal = new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()繼續執行
- 如果有攔截器鏈,把需要執行的目標對象,目標方法,攔截器鏈等資訊傳入創建一個
部分源碼
-
代理對象剛執行時的攔截方法
@Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Class<?> targetClass = null; Object target = null; try { if (this.advised.exposeProxy) { // 在必要時使調用可用。 oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 可能為空。儘可能晚地減少我們「擁有」目標的時間,以防它來自池... target = getTarget(); if (target != null) { targetClass = target.getClass(); } // 獲取攔截器鏈 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // 檢查是否有攔截器鏈 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 我們可以跳過創建方法調用:只需直接調用目標即可。請注意,最終的調用程式必須是 InvokerInterceptor,因此我們知道它只對目標執行反射操作,並且沒有熱插拔或花哨的代理。 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { // 我們需要創建一個方法調用(執行目標方法)... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = processReturnType(proxy, target, method, retVal); return retVal; } //... } -
包裝攔截器
@Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class<?> targetClass) { // 這有點棘手...我們必須首先處理介紹,但我們需要保持最終列表中的秩序。 List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // 有條件地添加它。 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { // 轉為攔截器 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { if (mm.isRuntime()) { // 在 getInterceptors()方法中創建新的對象實例不是問題,因為我們通常快取創建的鏈。 for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { // ...將其餘類型都轉為攔截器 } return interceptorList; }
⭐喵啊?鏈式調用通知方法
妙啊,執行過程設計的很有趣
所有準備都做好了(創建代理,增強器排序(倒序),增強器包裝獲取攔截器鏈),現在開始調用通知方法
執行過程
- 攔截器鏈的觸發過程:
- 如果沒有攔截器執行執行目標方法,或者攔截器的索引和攔截器數組-1大小一樣(執行到了最後一個攔截器)執行目標方法
- 鏈式獲取每一個攔截器,攔截器執行invoke方法,每一個攔截器等待下一個攔截器執行完成返回以後再來執行。攔截器鏈的機制,保證通知方法與目標方法的執行順序
5個攔截器(1個默認+4個自定義)的執行順序

執行上一節最後一步,獲取到攔截器鏈後執行new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()的proceed()方法
- 進入
proceed()方法,先判斷currentInterceptorIndex索引的值,默認是-1。this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1 -->{return invokeJoinpoint()} - 判斷是否有攔截器,如果沒有
0 - 1 = -1,正好等於默認值,沒有攔截器,就直接執行目標方法(業務)method.invoke(target,args) - 判斷是否是否要執行目標方法。程式多次執行,每載入一個攔截器,就+1,直到最後一個攔截器時,
this.currentInterceptorIndex=4(從-1到4),判斷4 == 5 - 1,攔截器載入完了,開始執行目標方法(業務)。 - 開始執行
-1 == 5 - 1不通過,表示有攔截器,執行this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex),從-1到0,獲取第0號攔截器。- 第 [0] 號攔截器是默認攔截器
ExposenvocationInterceptor調用invoke(this),參數this就是被代理目標類(業務類)CgliMethodInvocation,進入invoke(this),裡面調用mi[MethodInvocation].proceed(),這個proceed()就是本節第(1)步的proceed(),每個攔截器都會執行 - 獲取索引為 [1] 的攔截器
AspectJAfterThrowingAdvice前置攔截器->判斷->自增->invoke(this)->mi.proceed() - 獲取索引為 [2] 的攔截器
AfterReturingAdviceInterceptor返回通知攔截器->判斷->自增->invoke(this)->mi.proceed() - 獲取索引為 [3] 的攔截器
AspectJAfterAdvice->判斷->自增->invoke(this)->mi.proceed() - 獲取索引為 [4] 的攔截器
MethodBeforeAdviceInterceptor前置攔截器->判斷->自增->invoke(this){ 這裡與之前不同,因為是前置通知,所以要在目標方法執行前先執行增強方法,this.advice.before(mi.getMethod(),mi.getArguments(),mi.getThis())此時執行自定義的前置通知 }->mi.proceed() - 執行完最後一個攔截器,滿足條件
4 = 5 - 1,所以進入判斷執行invokeJoinpoint()利用反射執行目標方法(業務),到達底部同時準備返回
- 開始返回
- 執行完目標方法,返回到第 [3] 個攔截器
AspectJAfterAdvice執行最終通知,不管是否有異常finally{ invokeAdviceMethod(getJoinPointMatch(),null,null) } - 繼續返回,到第 [2] 個攔截器,
AfterReturingAdviceInterceptor執行返回通知,但是目標方法拋了異常,此處程式碼將異常繼續上拋throws Throwable,所以此處不做任何執行,如果沒有異常,就正常調用返回通知this.advice.afterReturning() - 繼續返回,到第 [1] 個攔截器,
AfterReturingAdviceInterceptor執行異常通知,它可以處理異常catch(Throwable ex){ if(){invokeAdviceMethod(getJoinPointMatch(),null,ex)} throw ex } - 繼續返回,自定義增強方法執行完了,執行第 [0] 個默認攔截器
- 增強方法執行過程:逆向執行攔截器,到達底部執行目標方法,返回時正向執行增強方法
部分源碼
-
獲取攔截器後繼續方法調用
@Override public Object proceed() throws Throwable { // 我們從 -1 的索引開始,並提前遞增。 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 每次將索引自增 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 在此處評估動態方法匹配器:靜態部分將已經過評估並發現匹配。 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 動態匹配失敗。 // 跳過此偵聽器並調用鏈中的下一個偵聽器。 return proceed(); } } else { // 調用這個 // 它是一個攔截器,所以我們只需調用它:在構造此對象之前,切入點將進行靜態計算。 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } -
依次調用攔截器的
mi.proceed()-
異常通知:AspectJAfterThrowingAdvice
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } } -
返回通知:AspectJAfterReturningAdvice
@Override public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; } -
後置通知:AspectJAfterAdvice
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } -
前置通知:AspectJMethodBeforeAdvice
@Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); }
-
-
調完攔截器之後執行目標方法
-
滿足條件執行目標方法
// 我們從-1的索引和早期的增量開始。 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } -
然後一層層向上返回攔截器,並處理通知(除了前置通知,因為它已經在目標方法前執行了)
-
如下:它返回到異常通知攔截器,並處理異常
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { //處理異常 invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
-
總結
@EnableAspectJAutoProxy開啟AOP功能@EnableAspectJAutoProxy會給容器中註冊一個組件AnnotationAwareAspectJAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator是一個後置處理器- 容器的創建流程:
registerBeanPostProcessors()註冊後置處理器,創建AnnotationAwareAspectJAutoProxyCreator對象finishBeanFactoryInitialization()初始化剩下的單實例bean- 創建業務邏輯組件和切面組件
AnnotationAwareAspectJAutoProxyCreator攔截組件的創建過程- 組件創建完之後,判斷組件是否需要增強
如果是:切面的通知方法,包裝成增強器(Advisor);給業務邏輯組件創建一個代理對象(cglib);
- 執行目標方法:
- 代理對象執行目標方法
CglibAopProxy.intercept()- 得到目標方法的攔截器鏈(增強器包裝成攔截器
MethodInterceptor) - 利用攔截器的鏈式機制,依次進入每一個攔截器進行執行;
- 效果:
正常執行:前置通知-》目標方法-》後置通知-》返回通知
出現異常:前置通知-》目標方法-》後置通知-》異常通知
- 得到目標方法的攔截器鏈(增強器包裝成攔截器




