摘要:版本從注解開始由于在本人實際應用中使用的是注解配置,也更傾向于了解的整個實現,而不僅僅是關鍵實現。于是本篇源碼解析,將會從注解開始。那么,便從的源碼引用開始吧。的引用先從源碼中找有引用到,用來判斷是否有該注解的代碼。
版本
spring 5.0.8.BUILD-SNAPSHOT
aspectjweaver 1.8.13
從注解開始由于在本人實際應用中使用的是注解配置AOP,也更傾向于了解Spring AOP的整個實現,而不僅僅是關鍵實現。于是本篇源碼解析,將會從注解開始。了解Spring AOP是怎么掃描Aspect配置,匹配,并生成AOP代理的。
注解@Aspect定了一個類為AOP的配置。那么,便從@Aspect的源碼引用開始吧。
@Aspect的引用先從源碼中找有引用到@Aspect,用來判斷Class是否有該注解的代碼。找到方法。
/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactory.java ... @Override public boolean isAspect(Class> clazz) { return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz)); } private boolean hasAspectAnnotation(Class> clazz) { return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null); } /** * We need to detect this as "code-style" AspectJ aspects should not be * interpreted by Spring AOP. */ private boolean compiledByAjc(Class> clazz) { // The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and // annotation-style aspects. Therefore there is no "clean" way to tell them apart. Here we rely on // an implementation detail of the AspectJ compiler. for (Field field : clazz.getDeclaredFields()) { if (field.getName().startsWith(AJC_MAGIC)) { return true; } } return false; } ...
isAspect(Class> clazz)用來判斷clazz對象是否包含Aspect.class注解并且未被AspectJ編譯過,其中hasAspectAnnotation(Class> clazz)內容很明顯就不多提。倒是compiledByAjc(Class> clazz)的實現比較特別。它的實現是用字段前綴來判斷是否為"code-style" aspects,看起來是一種比較Hack的方法。
這里我有一個疑惑點,就是"code-style" aspects和"annotation-style" aspects的具體所指,查了一圈也沒有看到明確的解釋。只在IDEA的幫助文檔Overview of AspectJ support這段上有看到相關的解釋。我的理解是"code-style"是由AspectJ Language所定義的aspect,會由AspectJ來編譯,而"annotation-style"則是由使用了@Aspect注解的Java語言所定義的aspect,如有錯誤煩請指出。入口在Bean的生命周期中
通過一步步閱讀和調試,可以一層一層向上找到org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java中有兩個入口。
postProcessBeforeInstantiation和postProcessAfterInitialization,是Bean生命周期中的兩個步驟:
postProcessBeforeInstantiation: 在Bean實例化之前執行
postProcessAfterInitialization: 在Bean初始化之后執行
postProcessBeforeInstantiation:/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java ... @Override public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { return null; } if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; } ...
這個方法的目的是將含有custom TargetSource的bean進行增強處理。可分為兩部份,前半部分利用緩存和幾個方法判斷是否需要增強。后半部分則進入主題判斷是否含有custom TargetSource。不過這里我對custom TargetSource不是特別理解,也沒有細看,因為通過@Aspect注解配置不會執行這里面的代碼,留著以后有時間再看。
這里還有另外兩個方法:
isInfrastructureClass(是否是基礎類,如Advice、Pointcut、Advisor、AopInfrastructureBean 及其超類)
shouldSkip(主要目的是判斷是否是已注冊的@Aspect配置Bean,其實掃描@Aspect注解配置的方法就在這里面被調用到了,這個后面再說)
postProcessAfterInitialization/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java .... /** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */ @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } /** * Wrap the given bean if necessary, i.e. if it is eligible for being proxied. * @param bean the raw bean instance * @param beanName the name of the bean * @param cacheKey the cache key for metadata access * @return a proxy wrapping the bean, or the raw bean instance as-is */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. 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; }
可以看到關鍵內容就在wrapIfNecessary里面。顧名思義:必要時轉成AOP代理。前半部分判斷是否是不需要增強的,跟postProcessBeforeInstantiation的前半部分有點類似。后半部分根據是否有合適的Advice方法,有則將Bean轉成代理。
好了,這里其實就是整個流程最關鍵的兩個地方了:
getAdvicesAndAdvisorsForBean(獲取適合該Bean的Advice方法,里面包含了掃描@Aspect注解配置Bean的方法)
createProxy(創建AOP代理,里面包含了AOP代理的實現)
這兩個方法的具體內容,將在接下來的文章介紹
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76764.html
摘要:而面向切面編程理所當然關注于切面,那么什么是切面可以理解為程序執行時的某個節點,或更具體一點,在某個方法執行之前,執行之后,返回之后等其它節點。術語一個切面,可以理解為一個切面模塊,將相關的增強內容寫進同一個切面。例如一個負責日志的切面。 AOP是什么 AOP全稱 Aspect-Oriented Programming 即面向切面編程。怎么樣,是不是感覺很熟悉?對,類似的還有面向過程編...
摘要:版本如何掃描接上一回,講到了方法,該方法的目的是獲取并生成。其中英文為源碼注釋。那么,以上便是通過掃描配置并生成的過程了。一些總結讀到這兒,如何掃描配置,生成類,并匹配對應的整個流程已經很清楚了。 版本 spring 5.0.8.BUILD-SNAPSHOT aspectjweaver 1.8.13 如何掃描Advice 接上一回,講到了getAdvicesAndAdvisorsF...
摘要:思考之所以會選擇為切入點,是因為通過命名可以看出這是用來構建代理強化對象的地方,并且由于是先將目標類加載到內存中,之后通過修改字節碼生成目標類的子類,因此我猜測強化是在目標類實例化后觸發的時候進行的。 【干貨點】 此處是【好好面試】系列文的第11篇文章。看完該篇文章,你就可以了解Spring中Aop的相關使用和原理,并且能夠輕松解答Aop相關的面試問題。更重要的是,很多人其實一看源碼就...
摘要:又是什么其實就是一種實現動態代理的技術,利用了開源包,先將代理對象類的文件加載進來,之后通過修改其字節碼并且生成子類。 在實際研發中,Spring是我們經常會使用的框架,畢竟它們太火了,也因此Spring相關的知識點也是面試必問點,今天我們就大話Aop。特地在周末推文,因為該篇文章閱讀起來還是比較輕松詼諧的,當然了,更主要的是周末的我也在充電學習,希望有追求的朋友們也盡量不要放過周末時...
摘要:接上一小節徹底征服之理論篇實戰看了上面這么多的理論知識不知道大家有沒有覺得枯燥哈不過不要急俗話說理論是實踐的基礎對有了基本的理論認識后我們來看一下下面幾個具體的例子吧下面的幾個例子是我在工作中所遇見的比較常用的的使用場景我精簡了很多有干擾我 接上一小節徹底征服 Spring AOP 之 理論篇 Spring AOP 實戰 看了上面這么多的理論知識, 不知道大家有沒有覺得枯燥哈. 不過不...
閱讀 2471·2023-04-25 21:41
閱讀 1647·2021-09-22 15:17
閱讀 1921·2021-09-22 10:02
閱讀 2433·2021-09-10 11:21
閱讀 2569·2019-08-30 15:53
閱讀 996·2019-08-30 15:44
閱讀 946·2019-08-30 13:46
閱讀 1125·2019-08-29 18:36