spring原始碼解析之AOP原理
一、準備工作
在這裡我先簡單記錄下如何實現一個aop:
AOP:【動態代理】 指在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式; 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; 三步: 1)、將業務邏輯元件和切面類都加入到容器中;告訴Spring哪個是切面類(@Aspect) 2)、在切面類上的每一個通知方法上標註通知註解,告訴Spring何時何地執行(切入點表示式)3)、開啟基於註解的aop模式;@EnableAspectJAutoProxy
我定義了一個除法方法,作為一個切面:
package com.kun.aop; public class MathCalculator { public int div(int i,int j){ System.out.println("MathCalculator...div..."); return i/j; } }
定義一個切面類:
packagecom.kun.aop; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * 切面類 * @author lfy * * @Aspect: 告訴Spring當前類是一個切面類 * */ @Aspect public class LogAspects { //抽取公共的切入點表示式 //1、本類引用 //2、其他的切面引用 @Pointcut("execution(public int com.kun.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.kun.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+"}"); } }
接下來是一個aop的配置:
package com.kun.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import com.kun.aop.LogAspects; import com.kun.aop.MathCalculator; @EnableAspectJAutoProxy @Configuration public class MainConfigOfAOP { //業務邏輯類加入容器中 @Bean public MathCalculator calculator(){ return new MathCalculator(); } //切面類加入到容器中 @Bean public LogAspects logAspects(){ return new LogAspects(); } }
通過以上程式碼我們就完成了一個簡單的aop操作,接下來我們根據原始碼來探究一下springAOP的實現原理。
二、從@EnableAspectJAutoProxy看起
檢視一下@EnableAspectJAutoProxy的定義:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { /** * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed * to standard Java interface-based proxies. The default is {@code false}. */ boolean proxyTargetClass() default false; }
我們發現它匯入了一個AspectJAutoProxyRegistrar元件,進一步檢視其程式碼:
/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.context.annotation; import org.springframework.aop.config.AopConfigUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import static org.springframework.context.annotation.MetadataUtils.*; /** * Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator * AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry} * as appropriate based on a given @{@link EnableAspectJAutoProxy} annotation. * * @author Chris Beams * @see EnableAspectJAutoProxy * @since 3.1 */ class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * Register, escalate, and configure the AspectJ auto proxy creator based on the value * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing * {@code @Configuration} class. */ public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAJAutoProxy = attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } } }
我們發現它實現了ImportBeanDefinitionRegistrar介面,這個介面可以向IOC容器中註冊bean。 由此可以推測aop利用AspectJAutoProxyRegistrar自定義給容器中註冊bean;BeanDefinetion。通過斷點我們發現
IOC容器中注入了一個internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator的bean,到此可以得出結論,@EnableAspectJAutoProxy給容器中註冊一個AnnotationAwareAspectJAutoProxyCreator。
三、AnnotationAwareAspectJAutoProxyCreator建立過程
首先檢視類圖:
在此需要關注兩點內容:
1)關注後置處理器SmartInstantiationAwareBeanPostProcessor(在bean初始化完成前後做事情)
2)關注自動裝配BeanFactory。
通過程式碼檢視,發現父類AbstractAutoProxyCreator中有後置處理器的內容;AbstactAdvisorAutoProxyCreator類中重寫了其父類AbstractAutoProxyCreator中setBeanFactory()方法,在AnnotationAwareAspectJAutoProxyCreator類中initBeanFactory()方法完成了自動裝配BeanFactory。分別在這兩處關注點打斷點來檢視其流程:
/** * Instantiate and invoke all registered BeanPostProcessor beans, * respecting explicit order if given. * <p>Must be called before any instantiation of application beans. */ protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, and the rest. 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 (isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, register the BeanPostProcessors that implement PriorityOrdered. OrderComparator.sort(priorityOrderedPostProcessors); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered. 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); } } OrderComparator.sort(orderedPostProcessors); registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular 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); // Finally, re-register all internal BeanPostProcessors. OrderComparator.sort(internalPostProcessors); registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector()); }
總結如下:
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);
=======以上是建立和註冊AnnotationAwareAspectJAutoProxyCreator的過程========
四、AnnotationAwareAspectJAutoProxyCreator的執行時機
通過以上步驟我們發現在IOC容器啟動時候,會通過一個@EnableAspectJAutoProxy註解注入AnnotationAwareAspectJAutoProxyCreator物件,並分析了該物件在IOC容器的啟動時進行建立的過程。接下來我們重點來分析一下AnnotationAwareAspectJProxyCreator物件執行的時機。
之前分析到AnnotationAwareAspectJAutoProxyCreator是一個後置處理器,可以猜測它在其他bean的初始化前後進行了特殊處理。我在它父類的postProcessBeforeInstantiation方法進行了斷點除錯,其方法呼叫棧如下:
通過對方法棧中原始碼的簡單檢視,我繼續完善了流程:
流程: 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); =======以上是建立和註冊AnnotationAwareAspectJAutoProxyCreator的過程======== AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor 4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;建立剩下的單例項bean 1)、遍歷獲取容器中所有的Bean,依次建立物件getBean(beanName); getBean->doGetBean()->getSingleton()-> 2)、建立bean 【AnnotationAwareAspectJAutoProxyCreator在所有bean建立之前會有一個攔截,InstantiationAwareBeanPostProcessor,
會呼叫postProcessBeforeInstantiation()】 1)、先從快取中獲取當前bean,如果能獲取到,說明bean是之前被建立過的,直接使用,否則再建立; 只要建立好的Bean都會被快取起來 2)、createBean();建立bean; AnnotationAwareAspectJAutoProxyCreator 會在任何bean建立之前先嚐試返回bean的例項 【BeanPostProcessor是在Bean物件建立完成初始化前後呼叫的】 【InstantiationAwareBeanPostProcessor是在建立Bean例項之前先嚐試用後置處理器返回物件的】 1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation 希望後置處理器在此能返回一個代理物件;如果能返回代理物件就使用,如果不能就繼續 1)、後置處理器先嚐試返回物件; bean = applyBeanPostProcessorsBeforeInstantiation(): 拿到所有後置處理器,如果是InstantiationAwareBeanPostProcessor; 就執行postProcessBeforeInstantiation if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } 2)、doCreateBean(beanName, mbdToUse, args);真正的去建立一個bean例項;和3.6流程一樣; 3)、
五、建立AOP代理
上一步我發現AnnotationAwareAspectJAutoProxyCreator在所有bean建立時進行了攔截,執行其中的postProcessBeforeInstantiation方法,接下來我們繼續通過斷點除錯檢視該方法的進行的操作。
首先方法內部會進行一系列的判斷,判斷當前bean是否在advisedBeans中(儲存了所有需要增強bean)、判斷當前bean是否是基礎型別的Advice、Pointcut、Advisor、AopInfrastructureBean、判斷是否是切面(是否實現了註解@Aspect)、判斷是否需要跳過等。
在判斷的過程中會拿到增強bean的相關的通知方法,並通過這些切面進行邏輯判斷。
執行完postProcessBeforeInstantiation方法進行通知方法的判斷後,執行postProcessAfterInitialization方法。
我們發現postProcessAfterInitialization方法會對切面進行一次包裝的處理。
在對物件包裝的過程中建立了一個代理物件。
我們細看建立代理物件的過程,發現在建立之前首先會根據切入點表示式對增強器進行一一匹配,最終拿到所有的增強器。
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (this.shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { this.evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); this.customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (this.advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(this.getProxyClassLoader()); }
建立代理物件過程中,會先建立一個代理工廠,獲取到所有的增強器(通知方法),將這些增強器和目標類注入代理工廠,再用代理工廠建立物件。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) { return new JdkDynamicAopProxy(config); } else { 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."); } else { return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config)); } } }
代理工廠會選擇JdkDynamicAopProxy或者CglibAopProxy,主要通過是否介面和是否配置cglib代理來選擇。最終工廠會建立一個代理增強的物件。我們繼續完善之前的流程.。
流程: 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); =======以上是建立和註冊AnnotationAwareAspectJAutoProxyCreator的過程======== AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor 4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;建立剩下的單例項bean 1)、遍歷獲取容器中所有的Bean,依次建立物件getBean(beanName); getBean->doGetBean()->getSingleton()-> 2)、建立bean 【AnnotationAwareAspectJAutoProxyCreator在所有bean建立之前會有一個攔截,InstantiationAwareBeanPostProcessor, 會呼叫postProcessBeforeInstantiation()】 1)、先從快取中獲取當前bean,如果能獲取到,說明bean是之前被建立過的,直接使用,否則再建立; 只要建立好的Bean都會被快取起來 2)、createBean();建立bean; AnnotationAwareAspectJAutoProxyCreator 會在任何bean建立之前先嚐試返回bean的例項 【BeanPostProcessor是在Bean物件建立完成初始化前後呼叫的】 【InstantiationAwareBeanPostProcessor是在建立Bean例項之前先嚐試用後置處理器返回物件的】 1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation 希望後置處理器在此能返回一個代理物件;如果能返回代理物件就使用,如果不能就繼續 1)、後置處理器先嚐試返回物件; bean = applyBeanPostProcessorsBeforeInstantiation(): 拿到所有後置處理器,如果是InstantiationAwareBeanPostProcessor; 就執行postProcessBeforeInstantiation if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } 2)、doCreateBean(beanName, mbdToUse, args);真正的去建立一個bean例項;和3.6流程一樣; 3)、 AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用: 1)、每一個bean建立之前,呼叫postProcessBeforeInstantiation(); 關心MathCalculator和LogAspect的建立 1)、判斷當前bean是否在advisedBeans中(儲存了所有需要增強bean) 2)、判斷當前bean是否是基礎型別的Advice、Pointcut、Advisor、AopInfrastructureBean, 或者是否是切面(@Aspect) 3)、是否需要跳過 1)、獲取候選的增強器(切面裡面的通知方法)【List<Advisor> candidateAdvisors】 每一個封裝的通知方法的增強器是 InstantiationModelAwarePointcutAdvisor; 判斷每一個增強器是否是 AspectJPointcutAdvisor 型別的;返回true 2)、永遠返回false 2)、建立物件 postProcessAfterInitialization; return wrapIfNecessary(bean, beanName, cacheKey);//包裝如果需要的情況下 1)、獲取當前bean的所有增強器(通知方法) Object[] specificInterceptors 1、找到候選的所有的增強器(找哪些通知方法是需要切入當前bean方法的) 2、獲取到能在bean使用的增強器。 3、給增強器排序 2)、儲存當前bean在advisedBeans中; 3)、如果當前bean需要增強,建立當前bean的代理物件; 1)、獲取所有增強器(通知方法) 2)、儲存到proxyFactory 3)、建立代理物件:Spring自動決定 JdkDynamicAopProxy(config);jdk動態代理; ObjenesisCglibAopProxy(config);cglib的動態代理; 4)、給容器中返回當前元件使用cglib增強了的代理物件; 5)、以後容器中獲取到的就是這個元件的代理物件,執行目標方法的時候,代理物件就會執行通知方法的流程;
六、獲取攔截器鏈
上一步分析了目標方法被代理並建立的過程,接下來我們分析目標方法被攔截並執行的過程。
因為要檢視目標方法的執行過程,所以我繼續在目標方法上進行斷點除錯。通過對MathCalculator檢視,可以發現它從IOC容器中取出已經是一個cglib代理物件了,其中包含增強方法和目標物件的一些詳細資訊。
緊接著斷點進入CglibAopProxy.intercept()攔截器,其中會獲取即將執行的目標方法的攔截器鏈。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class targetClass) { // This is somewhat tricky... we have to process introductions first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }
通過registry.getInterceptors(advisor)方法獲取所有的增強器,並將增強器轉為List<MethodInterceptor>,最終返回。
public Object proceed() throws Throwable { if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return this.invokeJoinpoint(); } else { Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice; return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed(); } else { return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this); } } }
之後,會將攔截器鏈和目標物件等傳入methodInvocation,並呼叫proceed()方法。該方法執行也是攔截器的觸發過程,也是目標方法的主要執行過程。
通過索引遍歷攔截器鏈中的所有的攔截器(封裝的增強器),並分別執行增強方法。每次執行攔截器方法索引自增,直至所有的增強方法執行完畢。
原始碼中有一個ExposeInvocationInterceptor物件會將MethodInvocation放入到ThreadLocal進行執行緒共享,檢視相關資料說方便同一執行緒中其他地方獲取通知方法,具體哪裡獲得,我暫時沒有找到,在後續工作學習中繼續深入檢視探究吧。
完善流程如下:
流程: 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); =======以上是建立和註冊AnnotationAwareAspectJAutoProxyCreator的過程======== AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor 4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;建立剩下的單例項bean 1)、遍歷獲取容器中所有的Bean,依次建立物件getBean(beanName); getBean->doGetBean()->getSingleton()-> 2)、建立bean 【AnnotationAwareAspectJAutoProxyCreator在所有bean建立之前會有一個攔截,InstantiationAwareBeanPostProcessor, 會呼叫postProcessBeforeInstantiation()】 1)、先從快取中獲取當前bean,如果能獲取到,說明bean是之前被建立過的,直接使用,否則再建立; 只要建立好的Bean都會被快取起來 2)、createBean();建立bean; AnnotationAwareAspectJAutoProxyCreator 會在任何bean建立之前先嚐試返回bean的例項 【BeanPostProcessor是在Bean物件建立完成初始化前後呼叫的】 【InstantiationAwareBeanPostProcessor是在建立Bean例項之前先嚐試用後置處理器返回物件的】 1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation 希望後置處理器在此能返回一個代理物件;如果能返回代理物件就使用,如果不能就繼續 1)、後置處理器先嚐試返回物件; bean = applyBeanPostProcessorsBeforeInstantiation(): 拿到所有後置處理器,如果是InstantiationAwareBeanPostProcessor; 就執行postProcessBeforeInstantiation if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } 2)、doCreateBean(beanName, mbdToUse, args);真正的去建立一個bean例項;和3.6流程一樣; 3)、 AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用: 1)、每一個bean建立之前,呼叫postProcessBeforeInstantiation(); 關心MathCalculator和LogAspect的建立 1)、判斷當前bean是否在advisedBeans中(儲存了所有需要增強bean) 2)、判斷當前bean是否是基礎型別的Advice、Pointcut、Advisor、AopInfrastructureBean, 或者是否是切面(@Aspect) 3)、是否需要跳過 1)、獲取候選的增強器(切面裡面的通知方法)【List<Advisor> candidateAdvisors】 每一個封裝的通知方法的增強器是 InstantiationModelAwarePointcutAdvisor; 判斷每一個增強器是否是 AspectJPointcutAdvisor 型別的;返回true 2)、永遠返回false 2)、建立物件 postProcessAfterInitialization; return wrapIfNecessary(bean, beanName, cacheKey);//包裝如果需要的情況下 1)、獲取當前bean的所有增強器(通知方法) Object[] specificInterceptors 1、找到候選的所有的增強器(找哪些通知方法是需要切入當前bean方法的) 2、獲取到能在bean使用的增強器。 3、給增強器排序 2)、儲存當前bean在advisedBeans中; 3)、如果當前bean需要增強,建立當前bean的代理物件; 1)、獲取所有增強器(通知方法) 2)、儲存到proxyFactory 3)、建立代理物件:Spring自動決定 JdkDynamicAopProxy(config);jdk動態代理; ObjenesisCglibAopProxy(config);cglib的動態代理; 4)、給容器中返回當前元件使用cglib增強了的代理物件; 5)、以後容器中獲取到的就是這個元件的代理物件,執行目標方法的時候,代理物件就會執行通知方法的流程; 3)、目標方法執行 ;
容器中儲存了元件的代理物件(cglib增強後的物件),這個物件裡面儲存了詳細資訊(比如增強器,目標物件,xxx); 1)、CglibAopProxy.intercept();攔截目標方法的執行 2)、根據ProxyFactory物件獲取將要執行的目標方法攔截器鏈; List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 1)、List<Object> interceptorList儲存所有攔截器 5 一個預設的ExposeInvocationInterceptor 和 4個增強器; 2)、遍歷所有的增強器,將其轉為Interceptor; registry.getInterceptors(advisor); 3)、將增強器轉為List<MethodInterceptor>; 如果是MethodInterceptor,直接加入到集合中 如果不是,使用AdvisorAdapter將增強器轉為MethodInterceptor; 轉換完成返回MethodInterceptor陣列;
3)、如果沒有攔截器鏈,直接執行目標方法;
攔截器鏈(每一個通知方法又被包裝為方法攔截器,利用MethodInterceptor機制)
4)、如果有攔截器鏈,把需要執行的目標物件,目標方法,
攔截器鏈等資訊傳入建立一個 CglibMethodInvocation 物件,
並呼叫 Object retVal = mi.proceed();
5)、攔截器鏈的觸發過程;
1)、如果沒有攔截器執行執行目標方法,或者攔截器的索引和攔截器陣列-1大小一樣(指定到了最後一個攔截器)執行目標方法;
2)、鏈式獲取每一個攔截器,攔截器執行invoke方法,每一個攔截器等待下一個攔截器執行完成返回以後再來執行;
攔截器鏈的機制,保證通知方法與目標方法的執行順序;
七、小結
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)、效果: 正常執行:前置通知-》目標方法-》後置通知-》返回通知 出現異常:前置通知-》目標方法-》後置通知-》異常通知