Spring源碼(二)---AOP

AOP 基本概念


    PointCut

        切入點簡單的理解就是定義了咱們要切入的位置(在某些類 某些方法上切入)。所以Spring Aop的PointCut實現應該知足過濾獲得目標類目標方法的需求。
java

        從PointCut接口定義咱們能夠看到ClassFilter和MethodMatcher,ClassFilter判斷那些類是要織入加強的,MethodMatcher是判斷哪些方法是知足織入加強的。spring

public interface Pointcut {
   ClassFilter getClassFilter();
   MethodMatcher getMethodMatcher();
   Pointcut TRUE = TruePointcut.INSTANCE;
}
public interface ClassFilter {

   /**
    * 判斷給定的clazz是否知足織入條件,知足則返回true
    */
   boolean matches(Class<?> clazz);
    /**
    * Canonical instance of a ClassFilter that matches all classes.
    * 這個默認的Filter是說全部的類都知足加強條件,都會返回true
    */
   ClassFilter TRUE = TrueClassFilter.INSTANCE;

}
public interface MethodMatcher {

   /**
    * Perform static checking whether the given method matches. 
      僅僅對方法的靜態匹配,不會檢驗方法具體參數值。
    */
   boolean matches(Method method, Class<?> targetClass);

   /**
    *是不是進行運行時方法匹配
    */
   boolean isRuntime();
    /**
    運行時 方法和方法參數同時都要進行匹配,知足則返回true
    */
   boolean matches(Method method, Class<?> targetClass, Object... args);
    /**
    * Canonical instance that matches all methods.
    * 默認全部的方法都匹配
    */
   MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

}

        默認的pointcut實現有:NameMatchMethodPointcut,JdkRegexpMethodPointcut,AspectJExpressionPointcut等。這裏對NameMatchMethodPointcut與AspectJExpressionPointcut作下簡單介紹。編程

        NameMatchMethodPointcut:僅僅經過對方法名字進行匹配織入位置。app

      其中從其父類StaticMethodMatcherPointcut源碼能夠看到以下代碼,說明該pointcut會默認全部的類都知足要求,即不對類作過濾。ide

private ClassFilter classFilter = ClassFilter.TRUE;
public void setClassFilter(ClassFilter classFilter) {
   this.classFilter = classFilter;
}
@Override
public ClassFilter getClassFilter() {
   return this.classFilter;
}

        AspectJExpressionPointcut:自己實現了MethodMatcher和Pointcut接口。該pointcut主要特色是支持AspectJ Expression。用戶可使用該語法定義poincut ,知足一些通配需求。工具

    

    Advice

        Advice就是在上面咱們經過Pointcut定義好的位置織入的具體邏輯。Advice翻譯過來叫作通知或者加強,這裏咱們統一叫作加強。加強 按照與業務代碼執行順序的前後位置主要分爲三類:
post

        BeforeAdvice:在業務代碼執行以前執行咱們織入的加強代碼。這裏BeforeAdvice接口去源碼中看其實沒有定義任何方法,是個空接口,咱們在寫具體的方法加強時是用的其子接口MethodBeforeAdvice。測試

        AopAroundAdvice:在業務代碼執行的先後織入加強代碼。這種環繞加強spring藉助aop alliance的MethodInterceptor實現。咱們通常直接實現MethodInterceptor接口,實現咱們加強代碼便可。this

        AfterAdvice:在業務代碼執行以後織入加強代碼。和BeforeAdvice同樣,它也是一個空接口。它具體又分爲AfterReturningAdvice,ThrowsAdvice。通常咱們實現直接實現AfterReturningAdvice接口便可。spa


    Aspect/Advisor

        spring 中的Aspect意思表明了一組poincut和advice,咱們常常利用aspect註解定義一個類,而後經過

<aop:aspectj-autoproxy/>自動去發現該aspect。advisor是指一個pointcut和對應的advice。從範圍上講aspect包含了advisor。

        這裏介紹下默認的advisor  DefaultPointcutAdvisor。

        從類圖接口繼承上看 該默認的Advisor繼承了Advisor 和PoincutAdvisor。Advisor是爲了組裝advice(加強),PointcutAdvisor在Advisor 接口基礎上添加了Pointcut,定義了getPointcut接口。DefaultPointcutAdvisor能夠看出一個對advisor和pointcut實現了getter/setter接口的類。


ProxyFactory/ProxyFactoryBean/AutoProxyCreator

    AopProxy 

        這裏叫作AopProxy不是很好,由於AopProxy是產生proxy的工具類,後面沒有加Factory,也許Spring是爲了不與ProxyFactory衝突。AopProxy定義了getProxy方法。具體實現類有JdkDynamicAopProxy,ObjenesisCglibAopProxy(CglibAopProxy的擴展類)

    這裏在介紹AopProxy產生proxy的原理以前先提下AdvisedSupport。AdvisedSupport類圖以下,它是AOP proxy配置管理的基類。

        它裏面維護了AOP proxy代理生產所需的配置,好比Advisors,TargetSource,AdvisorChainFactory。它的子類ProxyCreatorSupport實現了對AopProxy(JdkDynamicAopProxy,ObjenesisCglibAopProxy)具體類裏的注入,實現代理建立功能。ProxyCreatorSupport是咱們下面要介紹的ProxyFactory與ProxyFactoryBean的父類。

    JdkDynamicAopProxy:這裏咱們介紹下Jdk動態生產代理的原理。JdkDynamicAopProxy實現了JDK InvocationHandler接口。咱們先看下invoke方法具體代碼

//invocationHandler接口實現
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   MethodInvocation invocation;
   Object oldProxy = null;
   boolean setProxyContext = false;
   //獲取被代理的目標類實例
   TargetSource targetSource = this.advised.targetSource;
   Class<?> targetClass = null;
   Object target = null;

   try {
      //對Object上的基本方法不處理。
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      }
      if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;
      //判斷是否把代理放到利用ThreadLocal實現的AOP上下文中
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // 目標實例及目標類
      target = targetSource.getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }
      // 獲得咱們註冊的advice鏈,這一步很關鍵,它會根據咱們的註冊的pointcut來進行對目標類目標方法進行過濾,
      // 判斷方法是否知足定義的pointcut。下段代碼咱們具體分析
      //若是chain爲空說明不須要任何加強,
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         //沒有任何advice 直接對方法進行調用
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         //其中包含了代理類 目標對象 advice鏈 待調用方法。
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         //對advice進行調用。
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
           retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}
//同Proxy生成代理
@Override
public Object getProxy(ClassLoader classLoader) {
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//類DefaultAdvisorChainFactory

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, Class<?> targetClass) {

   List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

   for (Advisor advisor : config.getAdvisors()) {
      if (advisor instanceof PointcutAdvisor) {
         // Add it conditionally.
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
         //先根據ClassFilter來判斷目標類是否是知足Pointcut要求
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            //取得方法攔截器
            MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
            //得到pointcut上的MethodMatcher
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            //經過MethodMatcher來判斷方法是否符合poincut定義的需求。
            if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
               //若是是運行時MethodMatcher則須要對方法參數值進行匹配。
               if (mm.isRuntime()) {
                  // Creating a new object instance in the getInterceptors() method
                  // isn't a problem as we normally cache created chains.
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }
               else {
                  interceptorList.addAll(Arrays.asList(interceptors));
               }
            }
         }
      }
      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         }
      }
      else {
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }

   return interceptorList;
}

    

由於JdkDynamicAopProxy採用JDK動態代理原理 它只能對實現相應接口的類進行代理,不能對沒有接口的實現類進行代理。

    ObjenesisCglibAopProxy:CglibAOpProxy採用Cglib庫經過Enhancer來對類字節碼修改,實現AOP加強。CligbAopProxy能夠對沒有接口類進行代理,但不能對final類或方法繼續代理。

    ProxyFactory

        AOP proxies 代理工廠,主要是爲了編程( programmatic use)方式獲取proxy,而不是經過一個Bean Factory去獲取。ProxyFactory爲aop proxy提供了簡單的配置和獲取方法。

         下面我看一個簡單的例子

//定義一個advice
public class AopMethodBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before "+method.getName()+"-------");
    }
}
// action
public interface HelloAction {

    public String sayHello(String name);

    public String sayHelloA(String name);
}
//impl
public class HelloActionImpl implements HelloAction {

    @Override
    public String sayHello(String name) {
        System.out.println("hello "+name);
        return "hello "+name;
    }

    @Override
    public String sayHelloA(String name) {
        System.out.println("helloA "+name);
        return "helloA "+name;
    }
}
// ProxyFactoryTest
public class ProxyFactoryTest {


    @Test
    public void testGetProxy(){

        ProxyFactory proxyFactory=new ProxyFactory();

        //pointcut 匹配sayHello方法 
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();

        pointcut.setMappedNames(new String[] {"sayHello"});

        //define advisor (pointcut + advice)
        DefaultPointcutAdvisor beforeAdvisor=new DefaultPointcutAdvisor(pointcut,new AopMethodBeforeAdvice());
    
        HelloAction helloActionTarget=new HelloActionImpl();
        //這樣就能夠採用JDK proxy生成方法
        proxyFactory.setInterfaces(HelloAction.class);
        proxyFactory.setTarget(helloActionTarget);

        proxyFactory.addAdvisor(beforeAdvisor);

        HelloAction proxy=(HelloAction)proxyFactory.getProxy();

        proxy.sayHello("yao");
        proxy.sayHelloA("yaoA");

    }

}

        咱們debug進去看看一個aop 代理是如何運行的

        首先構造父類ProxyCreatorSupport,前面咱們介紹過,主要是增長屬性AopProxyFactory,生成一個AopPorxy(用來生產代理)

    DefaultAopProxyFactory主要是根據有無接口來生產JDK or Cglib AopProxy

    而後經過生成的AopProxy getProxy即獲取到代理對象。代理對象織入了advisor,具體執行就調用了咱們上面分析的JDK invoke 方法。(這裏假設採用JDK動態代理)

    ProxyFactoryBean

     ProxyFactoryBean和ProxyFactory功能同樣,只不過ProxyFactoryBean實現了FactoryBean,與Spring IOC容器結合起來了。下面是其類圖,它並實現了BeanFactoryAware感知接口,實現BeanFactory的自動注入。與ProxyFactory同樣都是ProxyCreatorSupport子類。

    咱們重點看下其getObject接口,

先判斷是不是產生單例代理仍是原型代理

產生單例代理就存下來,下次直接利用。具體過程都是先判處產生 createAopProxy(JDK or Cglib)而後getProxy便可。

原型的是每次連ProxyCreatorSupport都是新生成的,而後在createAopProxy,最後getProxy便可。

getProxy

    總之 ProxyFactoryBean的主要目的就是把Aop 嵌入到IOC 容器中。


    AutoProxyCreator

    上面咱們講了這麼多都是針對一個目標一個目標配置的,若是目標不少怎麼辦呢?這裏Spring IOC容器經過BeanPostProcessor 來實現Aop 代理自動建立,BeanPostProcessor。常見的自動代理建立有BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator。咱們看看默認的DefaultAdvisorAutoProxyCreator的類圖

AbstractAutoProxyCreator實現了BeanPostProcessor的postProcessBeforeInstantiation

AbstractAutoProxyCreator的createProxy方法。採用ProxyFactory實現。

    這裏測試用例就不寫了,文章還有不少介紹不全,慢慢修正補充。

本文連接:http://my.oschina.net/robinyao/blog/649518

相關文章
相關標籤/搜索