<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring 如何實現(xiàn) AOP,請不要再說 cglib 了!

          共 13180字,需瀏覽 27分鐘

           ·

          2020-10-01 10:54

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 6.5?分鐘。

          來自:juejin.im/post/6844903970658320391

          1. 從注解入手找到對應(yīng)核心類

          最近工作中我都是基于注解實現(xiàn) AOP 功能,常用的開啟 AOP 的注解是 @EnableAspectJAutoProxy,我們就從它入手。
          上面的動圖的流程的步驟就是:@EnableAspectJAutoProxy --> AspectJAutoProxyRegistrar -->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary -->AnnotationAwareAspectJAutoProxyCreator.class

          AnnotationAwareAspectJAutoProxyCreator 查看其中文注釋(如下),確定它就是 AOP 的核心類!-- 溫安適 20191020

          1. AspectJAwareAdvisorAutoProxyCreator的子類 ,用于處理當前應(yīng)用上下文中的注解切面

          2. 任何被AspectJ注解的類將自動被識別。

          3. 若SpringAOP代理模式可以識別,優(yōu)先使用Spring代理模式。

          4. 它覆蓋了方法執(zhí)行連接點

          5. 如果使用aop:include元素, 則只有名稱與include模式匹配的@aspectj bean才被視為切面 ,并由spring自動代理。

          6. 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)建代理的方式:

          1. 如果設(shè)置了 proxyTargetClass=true,一定是 CGLIB 代理

          2. 如果 proxyTargetClass=false,目標對象實現(xiàn)了接口,走 JDK 代理

          3. 如果沒有實現(xiàn)接口,走 CGLIB 代理

          4. 總結(jié)

          Spring 如何實現(xiàn) AOP?,您可以這樣說:

          1. AnnotationAwareAspectJAutoProxyCreator 是 AOP 核心處理類

          2. AnnotationAwareAspectJAutoProxyCreator 實現(xiàn)了 BeanProcessor,其中 postProcessAfterInitialization 是核心方法。

          3. 核心實現(xiàn)分為 2 步 getAdvicesAndAdvisorsForBean 獲取當前 bean 匹配的增強器 createProxy 為當前 bean 創(chuàng)建代理

          4. getAdvicesAndAdvisorsForBean 核心邏輯如下 a. 找所有增強器,也就是所有 @Aspect 注解的 Bean b. 找匹配的增強器,也就是根據(jù) @Before,@After 等注解上的表達式,與當前 bean 進行匹配,暴露匹配上的。c. 對匹配的增強器進行擴展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的數(shù)據(jù)值進行排序,越小的越靠前。

          5. createProxy 有 2 種創(chuàng)建方法,JDK 代理或 CGLIB a. 如果設(shè)置了 proxyTargetClass=true,一定是 CGLIB 代理 b. 如果 proxyTargetClass=false,目標對象實現(xiàn)了接口,走 JDK 代理 c. 如果沒有實現(xiàn)接口,走 CGLIB 代理。

          推薦閱讀:

          再見了SpringMVC,這個框架有點厲害,甚至干掉了Servlet!

          一行代碼搞定Spring Boot反爬蟲,防止接口盜刷

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公眾號內(nèi)回復「2048」,即可免費獲?。?!

          微信掃描二維碼,關(guān)注我的公眾號

          朕已閱?

          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产毛片在线看 | 免费毛片视频网站在线观看 | www.17c亚洲蜜桃 | 超碰97ol | 一区二区三区免费在线 |