正文:java
在上一篇,咱們對IOC核心部分流程已經分析完畢,相信小夥伴們有所收穫,從這一篇開始,咱們將會踏上新的旅程,即Spring的另外一核心:AOP!spring
首先,爲了讓你們能更有效的理解AOP,先帶你們過一下AOP中的術語:express
around
, before
和after
等等。許多AOP框架,包括Spring在內,都是以攔截器作通知模型的,並維護着一個以鏈接點爲中心的攔截器鏈。術語看完了,咱們先上個Demo回顧一下吧~spring-mvc
首先,使用EnableAspectJAutoProxy
註解開啓咱們的AOP緩存
@ComponentScan(basePackages = {"com.my.spring.test.aop"}) @Configuration @EnableAspectJAutoProxy public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class); IService service = context.getBean("service", IService.class); service.doService(); } }
寫一個接口mvc
public interface IService { void doService(); }
寫一個實現類app
@Service("service") public class ServiceImpl implements IService{ @Override public void doService() { System.out.println("do service ..."); } }
寫一個切面框架
@Aspect @Component public class ServiceAspect { @Pointcut(value = "execution(* com.my.spring.test.aop.*.*(..))") public void pointCut() { } @Before(value = "pointCut()") public void methodBefore(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法 【" + methodName + "】 的【前置通知】,入參:" + Arrays.toString(joinPoint.getArgs())); } @After(value = "pointCut()") public void methodAfter(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法 【" + methodName + "】 的【後置通知】,入參:" + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(value = "pointCut()") public void methodReturn(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法 【" + methodName + "】 的【返回通知】,入參:" + Arrays.toString(joinPoint.getArgs())); } @AfterThrowing(value = "pointCut()") public void methodThrow(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法 【" + methodName + "】 的【異常通知】,入參:" + Arrays.toString(joinPoint.getArgs())); } }
測試運行ide
執行目標方法 【doService】 的【前置通知】,入參:[] do service ... 執行目標方法 【doService】 的【返回通知】,入參:[] 執行目標方法 【doService】 的【後置通知】,入參:[]
以上模塊化
Demo看完了,運行效果也出來了,AOP已生效,但如何生效的呢?相比於咱們普通使用Bean的Demo,在這裏,咱們只不過加上了一個@EnableAspectJAutoProxy
註解以及一個標識了@Aspectj
的類,那麼咱們先看看@EnableAspectJAutoProxy
這個註解作了什麼吧~
如下是筆者所畫的大體流程圖
其中AspectJAutoProxyRegistrar
實現了ImportBeanDefinitionRegistrar
,因此在處理BeanFactoryPostProcessor
邏輯時將會調用registerBeanDefinitions
方法,此時就會把AnnotationAwareAspectJAutoProxyCreator
註冊到容器中,其中BeanFactoryPostProcessor
的邏輯就再也不說了,往期文章有過詳細分析。而AnnotationAwareAspectJAutoProxyCreator
的類圖以下:
咱們發現AnnotationAwareAspectJAutoProxyCreator
是實現了BeanPostProcessor
接口的類,因此它實際上是一個後置處理器,那麼,還記得在建立Bean過程當中的BeanPostProcessor
九次調用時機嗎?不記得也不要緊,AnnotationAwareAspectJAutoProxyCreator
起做用的地方是在bean的實例化前以及初始化後,分別對應着解析切面和建立動態代理的過程,如今,就讓咱們先來看看解析切面的過程吧~
解析切面的流程以下圖所示:
咱們已經瞭解到切面解析的過程是由AnnotationAwareAspectJAutoProxyCreator
完成的,而AnnotationAwareAspectJAutoProxyCreator
又繼承了AbstractAutoProxyCreator
,因此首先,咱們先會來到AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { // class類型是否爲(Advice, Pointcut, Advisor, AopInfrastructureBean) // shouldSkip中將會解析切面 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } }
調用到子類的AspectJAwareAdvisorAutoProxyCreator#shouldSkip
@Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // 尋找advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }
findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() { // 尋找實現了Advisor接口的類, 因爲咱們通常不會以接口的方式實現切面,這裏返回null List<Advisor> advisors = super.findCandidateAdvisors(); if (this.aspectJAdvisorsBuilder != null) { // 這裏將解析出全部的切面 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() { // aspectBeanNames有值則說明切面已解析完畢 List<String> aspectNames = this.aspectBeanNames; // Double Check if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 取出是Object子類的bean,其實就是全部的bean String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { // 得到該bean的class Class<?> beanType = this.beanFactory.getType(beanName); // 判斷是否有標識@AspectJ註解 if (this.advisorFactory.isAspect(beanType)) { // 將beanName放入集合中 aspectNames.add(beanName); // 將beanType和beanName封裝到AspectMetadata中 AspectMetadata amd = new AspectMetadata(beanType, beanName); // Kind默認爲SINGLETON if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 這裏會經過@Before @After等標識的方法獲取到全部的advisor List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { // 將獲取到的全部advisor放入緩存 this.advisorsCache.put(beanName, classAdvisors); } advisors.addAll(classAdvisors); } } } // 將全部解析過的beanName賦值 this.aspectBeanNames = aspectNames; return advisors; } } } // aspectNames不爲空,意味有advisor,取出以前解析好的全部advisor List<Advisor> advisors = new ArrayList<>(); // 獲取到全部解析好的advisor for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } return advisors; }
advisorFactory.getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // 獲取到標識了@AspectJ的class,其實就是剛剛封裝的class Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); // 獲取className String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); List<Advisor> advisors = new ArrayList<>(); // 拿出該類除了標識@PointCut的全部方法進行遍歷 getAdvisorMethods時會對method進行一次排序 // 排序順序 Around, Before, After, AfterReturning, AfterThrowing for (Method method : getAdvisorMethods(aspectClass)) { // 獲取到advisor Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName); if (advisor != null) { // 加入到集合中 advisors.add(advisor); } } }
咱們先看下getAdvisorMethods
方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) { final List<Method> methods = new ArrayList<>(); // 循環遍歷該類和父類的全部方法 ReflectionUtils.doWithMethods(aspectClass, method -> { // 排除@PointCut標識的方法 if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) { methods.add(method); } }, ReflectionUtils.USER_DECLARED_METHODS); if (methods.size() > 1) { // 以Around, Before, After, AfterReturning, AfterThrowing的順序自定義排序 methods.sort(METHOD_COMPARATOR); } return methods; }
不知道小夥伴們對ReflectionUtils.doWithMethods這個工具類熟不熟悉呢,這個工具類在以前分析Bean建立過程時但是出現了好屢次呢,而且咱們也是可使用的
如今,已經獲取到切面中的全部方法了,那麼接下來就該對這些方法解析並進行封裝成advisor了~
getAdvisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { // 獲取方法上的切點表達式 AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); // 封裝成對象返回,建立對象時將會解析方法建立advice return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
獲取切點表達式的過程其實很是簡單,便是解析方法上的註解,取出註解上的value便可
getPointcut
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 查找方法上和AspectJ相關注解 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); // 設置切點表達式 AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // PointcutExpression 爲註解上value屬性的值 ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory != null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; }
new InstantiationModelAwarePointcutAdvisorImpl,在這裏,纔會真正建立出advice
public InstantiationModelAwarePointcutAdvisorImpl(){ //...省略賦值過程... // 實例化出advice this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); }
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) { // 獲取advice,aspectJAdviceMethod爲方法,aspectName爲切面類 Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); return (advice != null ? advice : EMPTY_ADVICE); }
public Advice getAdvice(){ // 根據方法獲取到註解信息 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); AbstractAspectJAdvice springAdvice; // 根據註解類型返回對象,建立對象的過程都是同樣的,都是調用父類的構造方法 // candidateAdviceMethod爲切面的方法,expressionPointcut是切點 switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut return null; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; //...省略其餘的advice default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } return springAdvice; }
springAdvice已建立完畢,意味着切面中的某個方法已經解析完畢了,其餘的方法解析過程大體也是類似的
其實解析切面自己並不複雜,只是Spring中將切面類封裝來封裝去容易令人混亂,如buildAspectJAdvisors
方法中,封裝了一個AspectMetadata amd = new AspectMetadata(beanType, beanName);
,又當即發起斷定amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON
,其實這裏徹底能夠變爲AjTypeSystem.getAjType(currClass).getPerClause().getKind() == PerClauseKind.SINGLETON
,AjTypeSystem.getAjType(currClass)
爲new AspectMetadata
的一部分邏輯,筆者這裏給你們總結一下吧。
首先,循環全部的beanName,找到帶有@Aspectj註解的class, 獲取到class中的全部方法進行遍歷解析,取出方法註解上的值(切點:pointcut),而後把方法,切點表達式,封裝了BeanFactory,BeanName的factory封裝成相應的SpringAdvice, 由SpringAdvice和pointcut組合成一個advisor。
切面已經解析完畢,接下來,咱們就來看看如何把解析出的切面織入到目標方法中吧
但,在這以前,還有必要給小夥伴們補充一點前置知識。
咱們知道,一個bean是否可以被aop代理,取決於它是否知足代理條件,即爲是否可以被切點表達式所命中,而在Spring AOP中,bean與切點表達式進行匹配的是AspectJ實現的,並不是Spring所完成的,因此咱們先來看看AspectJ如何匹配出合適的bean的吧
首先須要引入org.aspectj:aspectjweaver
依賴
一個Service,包名爲com.my.spring.test.aop
package com.my.spring.test.aop; /** * 切點表達式能夠匹配的類 * */ public class ServiceImpl{ /** * 切點表達式能夠匹配的方法 */ public void doService() { System.out.println("do service ..."); } public void matchMethod() { System.out.println("ServiceImpl.notMatchMethod"); } }
而後,咱們本身封裝一個用於匹配的工具類,具體功能你們看註釋哈哈
package com.my.spring.test.aspectj; import org.aspectj.weaver.tools.PointcutExpression; import org.aspectj.weaver.tools.PointcutParser; import org.aspectj.weaver.tools.ShadowMatch; import java.lang.reflect.Method; /** * aop工具 */ public class AOPUtils { // AspectJ的固定寫法,獲取一個切點解析器 static PointcutParser parser = PointcutParser .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution( PointcutParser.getAllSupportedPointcutPrimitives(), ClassLoader.getSystemClassLoader()); // 切點表達式 private static PointcutExpression pointcutExpression; /** * 初始化工具類,咱們須要先獲取一個切點表達式 * * @param expression 表達式 */ public static void init(String expression){ // 解析出一個切點表達式 pointcutExpression = parser.parsePointcutExpression(expression); } /** * 第一次篩選,根據類篩選,也叫作粗篩 * * @param targetClass 目標類 * @return 是否匹配 */ public static boolean firstMatch(Class<?> targetClass){ // 根據類篩選 return pointcutExpression.couldMatchJoinPointsInType(targetClass); } /** * 第二次篩選,根據方法篩選,也叫作精篩,精篩經過則說明徹底匹配 * ps: 也可使用該方法進行精篩,粗篩的目的是提升性能,第一次直接過濾掉不合適的類再慢慢精篩 * * @param method 方法 * @return 是否匹配 */ public static boolean lastMatch(Method method){ // 根據方法篩選 ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method); return shadowMatch.alwaysMatches(); } }
測試
public class AOPUtilsTest { public static void main(String[] args) throws NoSuchMethodException { // 定義表達式 String expression = "execution(* com.my.spring.test.aop.*.*(..))"; // 初始化工具類 AOPUtils.init(expression); // 粗篩 boolean firstMatch = AOPUtils.firstMatch(ServiceImpl.class); if(firstMatch){ System.out.println("第一次篩選經過"); // 正常狀況應該是獲取全部方法進行遍歷,我這裏偷懶了~ Method doService = ServiceImpl.class.getDeclaredMethod("doService"); // 精篩 boolean lastMatch = AOPUtils.lastMatch(doService); if(lastMatch){ System.out.println("第二次篩選經過"); } else{ System.out.println("第二次篩選未經過"); } } else { System.out.println("第一次篩選未經過"); } } }
結果(就不截圖了,懷疑的小夥伴能夠本身試試~)
第一次篩選經過 第二次篩選經過
當咱們新建一個類Test
,把切點表達式換成
execution(* com.my.spring.test.aop.Test.*(..))
測試結果爲
第一次篩選未經過
再把切點表達式換成指定的方法
execution(* com.my.spring.test.aop.*.matchMethod(..))
結果
第一次篩選經過 第二次篩選未經過
到這裏,小夥伴們應該明白了AspectJ的使用方法吧
接下來,咱們就來看看Spring是如何使用AspectJ匹配出相應的advisor並建立代理對象的吧,如下爲建立代理對象的大體路程圖
建立代理對象是在bean初始化後完成的,因此對應的beanPostProcessor
調用時機爲postProcessAfterInitialization
AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { // 獲取緩存key值,其實就是beanName Object cacheKey = getCacheKey(bean.getClass(), beanName); // 判斷緩存中是否有該對象,有則說明該對象已被動態代理,跳過 if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 根據bean獲取到匹配的advisor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 建立代理對象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); return proxy; } return bean; }
getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // 獲取合適的advisor List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); return advisors.toArray(); }
findEligibleAdvisors
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 先獲取到全部的advisor, 這裏和解析過程相同,因爲已經解析好,因此會直接從緩存中取出 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 篩選出匹配的advisor List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 增長一個默認的advisor extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { // 排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { // 查找匹配的advisor return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); }
findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz){ List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { // 判斷是否匹配 if (canApply(candidate, clazz, hasIntroductions)) { // 加入到合適的advisors集合中 eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
canApply
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; // 判斷是否匹配 return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }
canApply
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { // 第一次篩選,對class篩選判斷是否知足匹配條件 // 這裏將會初始化切點表達式 if (!pc.getClassFilter().matches(targetClass)) { return false; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); // 循環全部方法進行第二次篩選,判斷是否有方法知足匹配條件 for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
pc.getClassFilter()
public ClassFilter getClassFilter() { obtainPointcutExpression(); return this; }
obtainPointcutExpression
private PointcutExpression obtainPointcutExpression() { if (this.pointcutExpression == null) { // 確認類加載器 this.pointcutClassLoader = determinePointcutClassLoader(); // 建立切點表達式 this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader); } return this.pointcutExpression; }
buildPointcutExpression
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) { // 初始化切點解析器 PointcutParser parser = initializePointcutParser(classLoader); PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length]; for (int i = 0; i < pointcutParameters.length; i++) { pointcutParameters[i] = parser.createPointcutParameter( this.pointcutParameterNames[i], this.pointcutParameterTypes[i]); } // 使用切點解析器進行解析表達式獲取切點表達式 return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()), this.pointcutDeclarationScope, pointcutParameters); }
initializePointcutParser
private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) { // 得到切點解析器 PointcutParser parser = PointcutParser .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution( SUPPORTED_PRIMITIVES, classLoader); parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler()); return parser; }
pc.getClassFilter即是完成了以上事情,此時再進行調用matchs方法
public boolean matches(Class<?> targetClass) { PointcutExpression pointcutExpression = obtainPointcutExpression(); // 使用切點表達式進行粗篩 return pointcutExpression.couldMatchJoinPointsInType(targetClass); }
introductionAwareMethodMatcher.matches 一樣如此
以上即是尋找合適的advisor的過程,下面,就是經過這些advisor進行建立動態代理了
createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); // 將specificInterceptors(如今是Object)轉化爲Advisor返回 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 賦值到proxyFactory的advisors屬性中 proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); // 建立動態代理 return proxyFactory.getProxy(getProxyClassLoader()); }
proxyFactory.getProxy
public Object getProxy(@Nullable ClassLoader classLoader) { // 建立代理對象 return createAopProxy().getProxy(classLoader); }
createAopProxy
protected final synchronized AopProxy createAopProxy() { // 建立AOP代理對象 return getAopProxyFactory().createAopProxy(this); }
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // @EnableAspectJAutoProxy的proxyTargetClass是否配置爲true 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."); } // 如何是接口則建立jdk動態代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // cglib動態代理 return new ObjenesisCglibAopProxy(config); } // 默認是jdk動態代理 else { return new JdkDynamicAopProxy(config); } }
public Object getProxy(@Nullable ClassLoader classLoader) { // 獲取到代理的接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 建立jdk代理,傳入的爲JdkDynamicAopProxy對象,裏面包含了被代理的bean以及匹配的advisor return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
動態代理建立完成~
對象都給你建立好了,接下固然是開..發起調用咯
如下是調用的大體流程圖
代理對象被調用的是invoke方法,咱們所建立的代理對象爲JdkDynamicAopProxy
,因此
JdkDynamicAopProxy#invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; // 取出包裝了被代理bean的對象->建立代理對象時的SingletonTargetSource, advised爲ProxyFactory TargetSource targetSource = this.advised.targetSource; Object target = null; // 拿到bean target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 將全部advisor中的advice取出,並轉化爲對應的interceptor List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // 建立一個最外層的MethodInvocation用於發起調用 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 發起鏈式調用 Object retVal = invocation.proceed(); return retVal; }
咱們先看獲取interceptor的過程
getInterceptorsAndDynamicInterceptionAdvice
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { // 將全部advisor中的advice取出並封裝成intercept return this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass); }
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { // 建立一個advisor適配器的註冊器用於轉化advice,建立時將默認註冊三個適配器 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); // 循環遍歷全部advisor for (Advisor advisor : advisors) { // 將advisor中的advice轉化爲interceptor MethodInterceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); return interceptorList; } }
GlobalAdvisorAdapterRegistry.getInstance() 類初始化時調用靜態方法
private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry() public static AdvisorAdapterRegistry getInstance() { return instance; }
public DefaultAdvisorAdapterRegistry() { // 註冊三個適配器 registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); }
public void registerAdvisorAdapter(AdvisorAdapter adapter) { // 將適配器加入集合 this.adapters.add(adapter); }
registry.getInterceptors 這裏麪包含了advice轉化成interceptor的過程
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); // advice自己是否就是MethodInterceptor if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { // 判斷advice是哪一個advice 如:(advice instanceof MethodBeforeAdvice) if (adapter.supportsAdvice(advice)) { // 將advice封裝到對應的interceptor interceptors.add(adapter.getInterceptor(advisor)); } } return interceptors.toArray(new MethodInterceptor[0]); }
若adapter爲MethodBeforeAdviceAdapter
,則
public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); }
其餘advice轉化過程相同
以上,便將全部的advice轉化成了interceptor,接下來,則是經典的鏈式遞歸調用過程
如下過程小夥伴們能夠對照流程圖閱讀,畢竟遞歸仍是有些複雜,須要必定的功底
ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable { // currentInterceptorIndex 初始值爲-1 // 當currentInterceptorIndex等於advice的數量減一時,則調用目標方法 // 因爲advice已排好序,因此調用順序爲before, after, afterReturn, afterThrowing // 注意,並不是調用到相應的advice就會執行advice方法,這裏是相似遞歸調用的方式,會存在一個歸過程 // 有些是遞的時候發起調用,如beforeAdvice, 但有些則是歸的時候發起調用,如afterAdvice // 遞歸的終止條件則是這下面這個return invokeJoinpoint(); if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // currentInterceptorIndex自增並獲取到interceptor Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); // 將interceptro強轉爲MethodInterceptor發起調用 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }
此時currentInterceptorIndex值爲0,而咱們的advice爲4個(去除了默認的),因此當currentInterceptorIndex爲3時便會調用咱們的實際方法
首先調用的是MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { // 調用前置通知 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); }
mi爲傳入的this,全部mi.proceed()將會回到最開始的方法
再次循環,此時currentInterceptorIndex值爲1
調用的是AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } finally { // finally意味着無論怎樣都會被調用 invokeAdviceMethod(getJoinPointMatch(), null, null); } }
繼續,此時currentInterceptorIndex值爲2
調用的是AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
繼續,此時currentInterceptorIndex值爲3
調用的是AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { // 調用異常通知 invokeAdviceMethod(getJoinPointMatch(), null, ex); } // 往外拋出異常 throw ex; } }
因此若是咱們的業務方法發生了異常,會調用到異常通知,而這裏又把異常往外拋,因此afterReturn就會被跳過直接到after的finally方法
如今currentInterceptorIndex值爲3了,再回調最初的方法中時,就會調用到咱們的業務方法了。調用完畢則進行歸的過程,調用過程便結束了。
以上,即是整個AOP的過程了
本篇文章中涉及到圖片的矢量圖地址爲:https://www.processon.com/view/link/5fa8afdae401fd45d109f257,有須要的小夥伴可自取
下文預告:Spring源碼分析之事務管理(上)
另外筆者公衆號:奇客時間,有更多精彩的文章,有興趣的同窗,能夠關注