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

相关文章
相关标签/搜索