一、准備工作
在這里我先簡單記錄下如何實現一個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; } }
定義一個切面類:
package com.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)、效果: 正常執行:前置通知-》目標方法-》后置通知-》返回通知 出現異常:前置通知-》目標方法-》后置通知-》異常通知