动态代理以及对应Spring中AOP源码分析

  AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理。

  我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理。以下是两种动态代理的实现方式:

//JDK动态代理
public class JDKProxy implements InvocationHandler {
 
  private Object object;// 被代理人
 
  //这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理。但是要注意下面的newProxyInstance()中的参数
  public Object getInstance(Object object) {
    this.object = object;
    //与cglib的区别在于这里构建代理对象的时候需要传入被代理对象的接口对象,第二个参数。而cglib不需要被代理对象实现任何接口即可   
    return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
  }
 
    //代理对象真正调用的方法
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("doSomething---------start");
    method.invoke(object, args);
    System.out.println("doSomething---------end");
    return null;
  }
 
}

//CGlib动态代理
public class CglibProxy implements MethodInterceptor {
  private Object targetObject;
 
  // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
  public Object getInstance(Object target) {
    this.targetObject = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(target.getClass());
    enhancer.setCallback(this);
    //注意该处代理的创建过程
    Object proxyObj = enhancer.create();
    return proxyObj;// 返回代理对象
  }
 
    //代理对象真正调用的方法
  @Override
  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    Object obj = null;
    System.out.println("doSomething---------start");
    obj = method.invoke(targetObject, args);
    System.out.println("doSomething---------end");
    return obj;
  }
 
}

  具体两种动态代理的差异在网上有很多各个方面的比较,在这里我就不再赘述。下面我再说说在Spring 5.0.3.RELEASE中实现AOP的原理(我的github中也有详细的源码注释)。

  在注解版的Spring AOP当中我们会有如下的代码配置,其中@EnableAspectJAutoProxy便是开启AOP支持的关键。

@EnableAspectJAutoProxy //开启基于注解的AOP模式
@Configuration
@ComponentScan(value = {"com.aop"})
public class AnnotationAopConfig {

@Bean("student")
    public Student getStudent() { //把我们普通的Java Bean定义出来交给IOC容器管理
        return new Student();
    }

@Bean
    public LogAspect getLogAspect() { //定义切面类
        return new LogAspect();
    }
}

  我们跟踪一下@EnableAspectJAutoProxy的源码来看看它的定义,会发现它利用@Import导入了AspectJAutoProxyRegistrar.class组件:代码块一

  由AspectJAutoProxyRegistrar.Class的定义可知其实现了ImportBeanDefinitionRegistrar接口,所以在IOC容器初始化的时候会调用该类的registerBeanDefinitions方法。通过观察该方法实现,我们可以看到一行关键的代码AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);:代码块二

  这行代码中所需要注册的到底是什么东西呢?我们进一步一探究竟。在持续跟入代码的过程中我们可以找到这么一块代码:return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);:代码块三

  观察源码可以得知,该方法会将AnnotationAwareAspectJAutoProxyCreator类封装为一个RootBeanDefinition然后添加到BeanDefinition的注册类当中以AUTO_PROXY_CREATOR_BEAN_NAME。我们也可以找到关于AUTO_PROXY_CREATOR_BEAN_NAME的定义:代码块四

  我们再分析一下AnnotationAwareAspectJAutoProxyCreator.Class的源码,看看此类到底有何特别之处。观察源码我们可以发现AnnotationAwareAspectJAutoProxyCreator是BeanPostPrcsessor的子类:代码块五

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/1e81645450fe6d20872ce78e9eaaccc0.html