溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring如何實現(xiàn)AOP

發(fā)布時間:2021-06-28 17:43:56 來源:億速云 閱讀:126 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“Spring如何實現(xiàn)AOP”,在日常操作中,相信很多人在Spring如何實現(xiàn)AOP問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring如何實現(xiàn)AOP”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

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

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

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

/**
1.AspectJAwareAdvisorAutoProxyCreator的子類
,用于處理當(dāng)前應(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的部分類圖。
Spring如何實現(xiàn)AOP
從類圖看到了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獲取當(dāng)前bean匹配的增強器

  • createProxy為當(dāng)前bean創(chuàng)建代理
    要想明白核心流程還需要分析這2個方法。

3.讀重點方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean獲取當(dāng)前bean匹配的增強器

查看源碼如下,默認(rèn)實現(xiàn)在AbstractAdvisorAutoProxyCreator中。

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, 
      @Nullable TargetSource targetSource) {
   List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}

查閱findEligibleAdvisors方法,就干了3件事

  • 找所有增強器,也就是所有@Aspect注解的Bean

  • 找匹配的增強器,也就是根據(jù)@Before,@After等注解上的表達(dá)式,與當(dāng)前bean進行匹配,暴露匹配上的。

  • 對匹配的增強器進行擴展和排序,就是按照@Order或者PriorityOrdered的getOrder的數(shù)據(jù)值進行排序,越小的越靠前。

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   //找所有增強器
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   //找所有匹配的增強器
   List<Advisor> 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<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   List<Advisor> 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<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = this.aspectBeanNames;

   if (aspectNames == null) {
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         if (aspectNames == null) {
            List<Advisor> 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<Advisor> 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<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      List<Advisor> 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為當(dāng)前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ù)目標(biāo)對象創(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)用目標(biāo)方法
        proxy.sayHello();
    }
}
3.2.1 .3 jdk創(chuàng)建代理與cglib創(chuàng)建代理的區(qū)別
類型jdk創(chuàng)建動態(tài)代理cglib創(chuàng)建動態(tài)代理
原理java動態(tài)代理是利用反射機制生成一個實現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來處理cglib動態(tài)代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節(jié)碼生成子類來處理
核心類Proxy 創(chuàng)建代理利用反射機制生成一個實現(xiàn)代理接口的匿名類InvocationHandler 方法攔截器接口,需要實現(xiàn)invoke方法net.sf.cglib.proxy.Enhancer:主要增強類,通過字節(jié)碼技術(shù)動態(tài)創(chuàng)建委托類的子類實例net.sf.cglib.proxy.MethodInterceptor:方法攔截器接口,需要實現(xiàn)intercept方法
局限性只能代理實現(xiàn)了接口的類不能對final修飾的類進行代理,也不能處理final修飾的方法

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,目標(biāo)對象實現(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獲取當(dāng)前bean匹配的增強器 createProxy為當(dāng)前bean創(chuàng)建代理

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

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

到此,關(guān)于“Spring如何實現(xiàn)AOP”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI