Spring 如何實現(xiàn) AOP,請不要再說 cglib 了!
點擊上方藍色“小哈學(xué)Java”,選擇“設(shè)為星標”
回復(fù)“資源”獲取獨家整理的學(xué)習(xí)資料!


來源:juejin.im/post/6844903970658320391
1. 從注解入手找到對應(yīng)核心類 2. 畫核心類類圖,猜測核心方法 3. 讀重點方法,理核心流程 4. 總結(jié)
1. 從注解入手找到對應(yīng)核心類
最近工作中我都是基于注解實現(xiàn) AOP 功能,常用的開啟 AOP 的注解是 @EnableAspectJAutoProxy,我們就從它入手。

上面的動圖的流程的步驟就是:@EnableAspectJAutoProxy --> AspectJAutoProxyRegistrar -->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary -->AnnotationAwareAspectJAutoProxyCreator.class
“AnnotationAwareAspectJAutoProxyCreator 查看其中文注釋(如下),確定它就是 AOP 的核心類!-- 溫安適 20191020
AspectJAwareAdvisorAutoProxyCreator的子類 ,用于處理當前應(yīng)用上下文中的注解切面 任何被AspectJ注解的類將自動被識別。 若SpringAOP代理模式可以識別,優(yōu)先使用Spring代理模式。 它覆蓋了方法執(zhí)行連接點 如果使用aop:include元素, 則只有名稱與include模式匹配的@aspectj bean才被視為切面 ,并由spring自動代理。 Spring Advisors的處理請查閱,
org.springframework.aop
.framework.autoproxy.AbstractAdvisorAutoProxyCreator
@SuppressWarnings("serial")
public?class?AnnotationAwareAspectJAutoProxyCreator
extends?AspectJAwareAdvisorAutoProxyCreator?{
????//...省略實現(xiàn)
????}注解切面
雖然找到了核心類,但是并沒有找到核心方法!下面我們嘗試畫類圖確定核心方法。
2. 畫核心類類圖,猜測核心方法
AnnotationAwareAspectJAutoProxyCreator 的部分類圖。
AnnotationAwareAspectJAutoProxyCreator
從類圖看到了 AnnotationAwareAspectJAutoProxyCreator 實現(xiàn)了 BeanPostProcessor,而 AOP 功能應(yīng)該在創(chuàng)建完 Bean 之后執(zhí)行,猜測 AnnotationAwareAspectJAutoProxyCreator 實現(xiàn) BeanPostProcessor 的 postProcessAfterInitialization(實例化 bean 后處理)是核心方法。查看 AnnotationAwareAspectJAutoProxyCreator 實現(xiàn)的 postProcessAfterInitialization 方法,實際該方法在其父類 AbstractAutoProxyCreator 中。
//AbstractAutoProxyCreator中的postProcessAfterInitialization實現(xiàn)
@Override
public?Object?postProcessAfterInitialization(Object?bean,?String?beanName)
?throws?BeansException?{
???if?(bean?!=?null)?{
??????Object?cacheKey?=?getCacheKey(bean.getClass(),?beanName);
??????if?(!this.earlyProxyReferences.contains(cacheKey))?{
?????????return?wrapIfNecessary(bean,?beanName,?cacheKey);
??????}
???}
???return?bean;
}
發(fā)現(xiàn)發(fā)現(xiàn)疑似方法 wrapIfNecessary,查看其源碼如下,發(fā)現(xiàn) createProxy 方法。確定找對了地方。
protected?Object?wrapIfNecessary
????????(Object?bean,?String?beanName,?Object?cacheKey)?{
???if?(beanName?!=?null?&&?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;
???}
???//?創(chuàng)建代理
???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;
}
即 AnnotationAwareAspectJAutoProxyCreator 實現(xiàn) BeanPostProcessor 的 postProcessAfterInitialization 方法,在該方法中由 wrapIfNecessary 實現(xiàn)了 AOP 的功能。wrapIfNecessary 中有 2 個和核心方法
getAdvicesAndAdvisorsForBean 獲取當前 bean 匹配的增強器 createProxy 為當前 bean 創(chuàng)建代理 要想明白核心流程還需要分析這 2 個方法。
3. 讀重點方法,理核心流程
3.1 getAdvicesAndAdvisorsForBean 獲取當前 bean 匹配的增強器
查看源碼如下,默認實現(xiàn)在 AbstractAdvisorAutoProxyCreator 中。
@Override
@Nullable
protected?Object\[\]?getAdvicesAndAdvisorsForBean(
??????Class>?beanClass,?String?beanName,
??????@Nullable?TargetSource?targetSource)?{
???List?advisors?=?findEligibleAdvisors(beanClass,?beanName);
???if?(advisors.isEmpty())?{
??????return?DO\_NOT\_PROXY;
???}
???return?advisors.toArray();
}
查閱 findEligibleAdvisors 方法,就干了 3 件事
找所有增強器,也就是所有 @Aspect 注解的 Bean 找匹配的增強器,也就是根據(jù) @Before,@After 等注解上的表達式,與當前 bean 進行匹配,暴露匹配上的。 對匹配的增強器進行擴展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的數(shù)據(jù)值進行排序,越小的越靠前。
protected?List?findEligibleAdvisors(Class>?beanClass,?String?beanName)? {
???//找所有增強器
???List?candidateAdvisors?=?findCandidateAdvisors();
???//找所有匹配的增強器
???List?eligibleAdvisors?=?findAdvisorsThatCanApply(candidateAdvisors,?beanClass,?beanName);
???extendAdvisors(eligibleAdvisors);
???if?(!eligibleAdvisors.isEmpty())?{
???????//排序
??????eligibleAdvisors?=?sortAdvisors(eligibleAdvisors);
???}
???return?eligibleAdvisors;
}
AnnotationAwareAspectJAutoProxyCreator 重寫了 findCandidateAdvisors,下面我們看看具體實現(xiàn)了什么
3.1.1findCandidateAdvisors 找所有增強器,也就是所有 @Aspect 注解的 Bean
@Override
protected?List?findCandidateAdvisors()? {
???//?Add?all?the?Spring?advisors?found?according?to?superclass?rules.
???List?advisors?=?super.findCandidateAdvisors();
???//?Build?Advisors?for?all?AspectJ?aspects?in?the?bean?factory.
???if?(this.aspectJAdvisorsBuilder?!=?null)?{
??????//@Aspect注解的類在這里除了
??????advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
???}
???return?advisors;
}
從該方法我們可以看到處理 @Aspect 注解的 bean 的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。這個方法如下:
public?List?buildAspectJAdvisors()? {
???List?aspectNames?=?this.aspectBeanNames;
???if?(aspectNames?==?null)?{
??????synchronized?(this)?{
?????????aspectNames?=?this.aspectBeanNames;
?????????if?(aspectNames?==?null)?{
????????????List?advisors?=?new?ArrayList<>();
????????????aspectNames?=?new?ArrayList<>();
????????????//找到所有BeanName
????????????String\[\]?beanNames?=?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
??????????????????this.beanFactory,?Object.class,?true,?false);
????????????for?(String?beanName?:?beanNames)?{
???????????????if?(!isEligibleBean(beanName))?{
??????????????????continue;
???????????????}
???????????????//?必須注意,bean會提前暴露,并被Spring容器緩存,但是這時還不能織入。
???????????????Class>?beanType?=?this.beanFactory.getType(beanName);
???????????????if?(beanType?==?null)?{
??????????????????continue;
???????????????}
???????????????if?(this.advisorFactory.isAspect(beanType))?{
??????????????????//找到所有被@Aspect注解的類
??????????????????aspectNames.add(beanName);
??????????????????AspectMetadata?amd?=?new?AspectMetadata(beanType,?beanName);
??????????????????if?(amd.getAjType().getPerClause().getKind()?==?PerClauseKind.SINGLETON)?{
?????????????????????MetadataAwareAspectInstanceFactory?factory?=
???????????????????????????new?BeanFactoryAspectInstanceFactory(this.beanFactory,?beanName);
?????????????????????//解析封裝為Advisor返回
?????????????????????List?classAdvisors?=?this.advisorFactory.getAdvisors(factory);
?????????????????????if?(this.beanFactory.isSingleton(beanName))?{
????????????????????????this.advisorsCache.put(beanName,?classAdvisors);
?????????????????????}
?????????????????????else?{
????????????????????????this.aspectFactoryCache.put(beanName,?factory);
?????????????????????}
?????????????????????advisors.addAll(classAdvisors);
??????????????????}
??????????????????else?{
?????????????????????//?Per?target?or?per?this.
?????????????????????if?(this.beanFactory.isSingleton(beanName))?{
????????????????????????throw?new?IllegalArgumentException("Bean?with?name?'"?+?beanName?+
??????????????????????????????"'?is?a?singleton,?but?aspect?instantiation?model?is?not?singleton");
?????????????????????}
?????????????????????MetadataAwareAspectInstanceFactory?factory?=
???????????????????????????new?PrototypeAspectInstanceFactory(this.beanFactory,?beanName);
?????????????????????this.aspectFactoryCache.put(beanName,?factory);
?????????????????????advisors.addAll(this.advisorFactory.getAdvisors(factory));
??????????????????}
???????????????}
????????????}
????????????this.aspectBeanNames?=?aspectNames;
????????????return?advisors;
?????????}
??????}
???}
???if?(aspectNames.isEmpty())?{
??????return?Collections.emptyList();
???}
???List?advisors?=?new?ArrayList<>();
???for?(String?aspectName?:?aspectNames)?{
??????List?cachedAdvisors?=?this.advisorsCache.get(aspectName);
??????if?(cachedAdvisors?!=?null)?{
?????????advisors.addAll(cachedAdvisors);
??????}
??????else?{
?????????MetadataAwareAspectInstanceFactory?factory?=?this.aspectFactoryCache.get(aspectName);
?????????advisors.addAll(this.advisorFactory.getAdvisors(factory));
??????}
???}
???return?advisors;
}
這個方法可以概括為:
找到所有 BeanName 根據(jù) BeanName 篩選出被 @Aspect 注解的類 針對類中被 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解的方法,先按上邊的注解順序排序后按方法名稱排序,每一個方法對應(yīng)一個 Advisor。
3.2 createProxy 為當前 bean 創(chuàng)建代理。
3.2.1 創(chuàng)建代理的 2 種方式
眾所周知,創(chuàng)建代理的常用的 2 種方式是:JDK 創(chuàng)建和 CGLIB,下面我們就看看這 2 中創(chuàng)建代理的例子。
3.2.1 .1 jdk 創(chuàng)建代理的例子
import?java.lang.reflect.InvocationHandler;
import?java.lang.reflect.Method;
import?java.lang.reflect.Proxy;
public?class?JDKProxyMain?{
????public?static?void?main(String\[\]?args)?{
????????JDKProxyTestInterface?target?=?new?JDKProxyTestInterfaceImpl();
????????//?根據(jù)目標對象創(chuàng)建代理對象
????????JDKProxyTestInterface?proxy?=
?????????(JDKProxyTestInterface)?Proxy
?????????.newProxyInstance(target.getClass().getClassLoader(),
????????????????target.getClass().getInterfaces(),
????????????????new?JDKProxyTestInvocationHandler(target));
????????//?調(diào)用代理對象方法
????????proxy.testProxy();
????}
????interface?JDKProxyTestInterface?{
????????void?testProxy();
????}
????static?class?JDKProxyTestInterfaceImpl
????????????????????implements?JDKProxyTestInterface?{
????????@Override
????????public?void?testProxy()?{
????????????System.out.println("testProxy");
????????}
????}
???static?class?JDKProxyTestInvocationHandler
???????????????????????????implements?InvocationHandler?{
????????private??Object?target;
????????public?JDKProxyTestInvocationHandler(Object?target){
????????????this.target=target;
????????}
????????@Override
????????public?Object?invoke(Object?proxy,?Method?method,
?????????????????????????????Object\[\]?args)?throws?Throwable?{
????????????System.out.println("執(zhí)行前");
????????????Object?result=??method.invoke(this.target,args);
????????????System.out.println("執(zhí)行后");
????????????return?result;
????????}
????}
3.2.1 .2 cglib 創(chuàng)建代理的例子
import?org.springframework.cglib.proxy.Enhancer;
import?org.springframework.cglib.proxy.MethodInterceptor;
import?org.springframework.cglib.proxy.MethodProxy;
import?java.lang.reflect.Method;
public?class?CglibProxyTest?{
???static?class?CglibProxyService?{
????????public??CglibProxyService(){
????????}
????????void?sayHello(){
????????????System.out.println("?hello?!");
????????}
????}
????static?class?CglibProxyInterceptor?implements?MethodInterceptor{
????????@Override
????????public?Object?intercept(Object?sub,?Method?method,
?????????????Object\[\]?objects,?MethodProxy?methodProxy)
??????????????????????????????????????????throws?Throwable?{
????????????System.out.println("before?hello");
????????????Object?object?=?methodProxy.invokeSuper(sub,?objects);
????????????System.out.println("after?hello");
????????????return?object;
????????}
????}
????public?static?void?main(String\[\]?args)?{
????????//?通過CGLIB動態(tài)代理獲取代理對象的過程
????????Enhancer?enhancer?=?new?Enhancer();
????????//?設(shè)置enhancer對象的父類
????????enhancer.setSuperclass(CglibProxyService.class);
????????//?設(shè)置enhancer的回調(diào)對象
????????enhancer.setCallback(new?CglibProxyInterceptor());
????????//?創(chuàng)建代理對象
????????CglibProxyService?proxy=?(CglibProxyService)enhancer.create();
????????System.out.println(CglibProxyService.class);
????????System.out.println(proxy.getClass());
????????//?通過代理對象調(diào)用目標方法
????????proxy.sayHello();
????}
}
3.2.1 .3 jdk 創(chuàng)建代理與 cglib 創(chuàng)建代理的區(qū)別

3.2.2 Spring 如何選擇的使用哪種方式
Spring 的選擇選擇如何代理時在 DefaultAopProxyFactory 中。
public?class?DefaultAopProxyFactory?implements?AopProxyFactory,
????????????????????????????????????????????????????????Serializable?{
???@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))?{
????????????return?new?JdkDynamicAopProxy(config);
?????????}
?????????return?new?ObjenesisCglibAopProxy(config);
??????}
??????else?{
?????????return?new?JdkDynamicAopProxy(config);
??????}
???}
???//...
???}
config.isOptimize() 查看源碼注釋時發(fā)現(xiàn),這個是配置使用 cglib 代理時,是否使用積極策略。這個值一般不建議使用! config.isProxyTargetClass() 就是 @EnableAspectJAutoProxy 中的 proxyTargetClass 屬性。
“//exposeProxy=true AopContext 可以訪問,proxyTargetClass=true CGLIB 生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口
總結(jié)下 Spring 如何選擇創(chuàng)建代理的方式:
如果設(shè)置了 proxyTargetClass=true,一定是 CGLIB 代理 如果 proxyTargetClass=false,目標對象實現(xiàn)了接口,走 JDK 代理 如果沒有實現(xiàn)接口,走 CGLIB 代理
4. 總結(jié)
Spring 如何實現(xiàn) AOP?,您可以這樣說:
AnnotationAwareAspectJAutoProxyCreator 是 AOP 核心處理類 AnnotationAwareAspectJAutoProxyCreator 實現(xiàn)了 BeanProcessor,其中 postProcessAfterInitialization 是核心方法。 核心實現(xiàn)分為 2 步 getAdvicesAndAdvisorsForBean 獲取當前 bean 匹配的增強器 createProxy 為當前 bean 創(chuàng)建代理 getAdvicesAndAdvisorsForBean 核心邏輯如下 a. 找所有增強器,也就是所有 @Aspect 注解的 Bean b. 找匹配的增強器,也就是根據(jù) @Before,@After 等注解上的表達式,與當前 bean 進行匹配,暴露匹配上的。c. 對匹配的增強器進行擴展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的數(shù)據(jù)值進行排序,越小的越靠前。 createProxy 有 2 種創(chuàng)建方法,JDK 代理或 CGLIB a. 如果設(shè)置了 proxyTargetClass=true,一定是 CGLIB 代理 b. 如果 proxyTargetClass=false,目標對象實現(xiàn)了接口,走 JDK 代理 c. 如果沒有實現(xiàn)接口,走 CGLIB 代理
END
有熱門推薦?
1.?在華為鴻蒙 OS 上嘗鮮,我的第一個“hello world”,起飛!
2.?HTTP協(xié)議無狀態(tài)中的 "狀態(tài)" 到底指的是什么?
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點“在看”,關(guān)注公眾號并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。
謝謝支持喲 (*^__^*)

