Spring AOP 实现过程的总结

来源:互联网 发布:主机mac地址怎么查 编辑:程序博客网 时间:2024/06/04 17:52

 通过阅读SpringAOP源码,根据自己对源码的的理解,总结了Spring AOP是如何实现切面编程的。下面是根据自己理解画的流程图。



 

     用户通过配置XML <aop:aspectj-autoproxy>或@EnableAspectJAutoProxy注解来开启AOP自动代理对象,spring IOC容器在启动时会将配置的目标对象bean、切面及相关通知信息,解析成Advisor对象对应的BeanDefintion,并把代理对象的配置信息保存在ProxyConfig对象中。AbstractAutoProxyCreator继承了ProxyConfig,且实现了SmartInstantiationAwareBeanPostProcessor , BeanFactoryAware接口,这意味着当IOC容器启动时,会创建AbstractAutoProxyCreator对象,实现了BeanFactoryAware意味着,在AbstractAutoProxyCreator实例初始化阶段,BeanFactory自动注入DefaultListableBeanFactory工厂给AbstractAutoProxyCreator实例使用,有BeanFactory对象则可以通过getBean方法来访问容器中所有的通知对象Advisor相关信息.每当调用BeanFactory取得bean对象时,利用实现了SmartInstantiationAwareBeanPostProcessor的后置处理器功能,BeanFactory会在多个阶段自动调用AbstractAutoProxyCreator这个后置处理器的实现方法,这些实现方法用来判断该Bean是否需要代理,判断Bean是否需要的代理的依据是根据该bean对象是否在IOC容器中存在匹配的一个或多个通知Advisor对象,存在则需要代理,否则,就放过。


      根据bean对象的信息,从工厂中查询匹配的一个或多个通知Advisor对象,工厂通过Advisor.class类型查询到所有的Advisor类型,然后使用bean的class类型与Advisor对应的目标类型匹配,匹配成功的就取得该通知对象形成集合,并包装成Advisor接口对象集合。
   
      AdvisedSupport从用户定义的信息中取得包含了所有关于目标对象的信息和设置,还包括通知器拦截器等,这个对象是生成AOP代理方法的输入参数。代理工厂ProxyFactory继承了AdvisedSupport拥有了代理需要的配置,调用getProxy方法来得到代理对象Object。getProxy方法实现是根据bean的信息不同进行不同的代理方式:JDK代理或CGLIB代理。

      JDK代理对象和CGLIB代理对象,如果没有设置指定代理目标类,AOP自动识别进行代理,目标对象是接口类则使用JDK代理,否则就使用CGLIB代理。

      JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高.
  使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

    JDK代理三要素Proxy.newProxyInstance(类加载器,目标接口,InvocationHandler实现),JDKDynaimicAopProxy实现了InvocationHandler接口,并使用了AdvisedSupport中存在的目标接口,及设置的类加载器,进行JDK的动态代理。

    CGLIB创建代理主要是创建Enhancer enhancer,并通过AdvisedSupport设置相应的属性,比如目标类rootClass,如果由接口合并接口给代理类,最主要的是设置Callback集合和CallbackFilter,使用CallBackFilter可以根据方法的不同使用不同的Callback进行拦截和增强方法。其中最主要的使用于AOP的Callback是DynamicAdvisedInterceptor。

    代理完成后,在从IOC容器中访问该对象时,返回的将是一个代理对象。当调用该对象的方法时,则根据不同的代理,调用的代理方法也不同。

    使用JDK动态代理的回调方法是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

     使用CGLIB代理对象的回调方法是
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

        通过一系列的准备,已经为实现AOP的横切机奠定了基础,在这个基础上,AOP的Advisor已经可以通过AOPProxy代理对象的拦截机制,对需要它进行增强的target目标对象发挥切面的强大威力。

       可以把AOP的实现部分堪称有基础设施准备和AOP运行辅助这两部分组成,这里的AOPProxy代理对象的生成,可以看作是一个静态的AOP基础设施的建立过程。通过这个准备过程,把代理对象、拦截器这些待调用的部分都准备好,等待着AOP运行过程中对这些基础设施的使用。对于应用触发的AOP应用,会涉及AOP框架的运行和对AOP基础设施的使用。这些动态的运行部分,是从拦截器回调入口开始的。

      拦截器回调入口在JDK的invoke方法和CGLIB的 intercept方法中,当代理对象的方法被调用时,会触发相应的invoke方法或intercept方法,根据目标对象查询相应的拦截器链,如果不存在拦截器链直接调用目标对象的方法。否则就开始拦截器链的调用。JDK代理和CGLIB最终会殊途同归,它们对拦截器链的调用都是在ReflectiveMethodInvocation类中通过proceed方法实现的。ReflectiveMethodInvocation类实现了AOP 联盟定义方法拦截接口MethodInvocation,其中该接口中proceed()方法会逐个运行拦截器的拦截方法。ponitCut动态方法匹配成功的拦截器则进行方法的调用,这里使用了责任链的模式,主要代码这段interceptor.invoke(this);

      想一想自行车上的链子,一节链子连接另一节链子,当一节链子被齿轮带动,则这节链子会带动另一节链子。invoken方法是齿轮,interceptor和this都是MethodInterceptor的实例,相当于this是当前一节链,interceptor是后一节链,齿轮转动时,后一节链条需要当前的链条带动。就像当于interceptor.invoke(this); 而这里是拦截器链,是一个集合。相当于有多个的链条连接着。这样一链调用另一链循环着直到链条结束,当然现实的链条不能断,不然自行车就没法骑了。

      这些链条是如何形成的呢? 链条里是包含什么?invoke方法里处理什么呢?
        一个拦截器链需要实现MethodInterceptor接口,并实现Object invoke(MethodInvocation invocation)方法,在invoke方法中,如果需要下一个链条或得到前一个链条结果,则需要调用方法参数MethodInvocation的proceed()方法,进行下一个链条,默认进入ReflectiveMethodInvocation进行处理。

      Spring定义三个MethodInterceptor实现,分别为MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
分别为目标方法调用前进行前置通知拦截器,目标方法调用后进行后置通知拦截器,及目标对象出现异常进行异常通知拦截器,在方法invoke中,会调用通知的方法,通知的方法是用户定义的业务逻辑。因此MethodInterceptor需要通知对象Advisor,从Advisor中取得通知Advice。不同的方法拦截器需要的不同的通知对象,后置拦截器需要后置通知,前置拦截器需要前置通知,而异常拦截器需要异常通知,这里就需要把通知适配成拦截器。

       这些通知存在AdvisedSupport中,从AdvisedSupport对象中取得所有Advisor,Spring使用了适配器模式,取得这些Advisor包含的通知对象,根据通知对象的类型,适配成相应的拦截器,适配完的拦截器就形成了拦截器链。

      当ReflectiveMethodInvocation中interceptor.invoke(this);就会进行拦截器链的调用,调用的实际是通知方法即用户的业务逻辑,调用的前后根据invoke()方法中,业务逻辑在调用proceed()方法前还是后来决定。


下面引用:Spring技术内幕--深入解析Spring架构与设计原理

      在Spring的平台功能中,AOP是一个核心模块,通过对AOP的使用,极大地丰富了Spring框架地功能,比如在各种驱动组件的实现上,很灵活地运用了AOP的功能特性。
      在Spring AOP的基础实现中,可以了解Spring如何得到AOPProxy代理对象,一即如何利用AOPProxy代理对象来对拦截器进行处理。Proxy代理对象的使用,在SpringAOP的实现过程中是非常重要的一个部分,Spring AOP充分利用了像Java的Proxy、反射技术以及第三方字节码技术实现CGLIB这些技术方案,通过这些技术,完成了AOP需要的AopProxy代理对象的生成。回顾通过ProxyFactoryBean实现AOP的整个过程,可以看到,在它的实现中,首先需要对目标对象以及拦截器进行正确配置,以便AopProxy代理对象顺利产生;这些配置既可以通过配置ProxyFactoryBean的属性来完成,也可以通过编程式地使用ProxyFactory来实现,这两种AOP地使用方式只是在表面配置地方式上不同,对于内在地AOP实现原理它们是一样地。在生成AopProxy代理对象地时候,Spring AOP设计了专门的AopProxyFactory作为AopProxy代理对象的生产工厂,由它来负责产生相应的AopProxy代理对象,在使用ProxyFactoryBean得到AopProxy代理对象的时候,默认使用的AopProxy代理对象的生产工厂是DefaultAopProxyFactory对象。这个对象是AopProxy生产过程中一个比较重要的类,它定义了AopProxy代理对象的生成策略,从而决定使用那种AopProxy代理对象的生成技术(是使用JDK的动态代理还是CGLIB)来完成生产任务。而最终的AOPProxy代理对象的产生,则交给了JdkDynamicAopProxy和Cglib2AopProxy这两个具体的工厂来完成,它们使用了不同的生产技术。

      在得到AopProxy代理对象后,在代理的接口方法被调用执行的时候,也就是当AopProxy暴露代理的方法被调用的时候,前面定义的Proxy机制就起作用了。当Proxy对象暴露的方法被调用时,并不是直接运行目标对象的调用方法,而是根据Proxy的定义,改变原有的目标对象方法调用的运行轨迹。这种改变体现在,首先会触发对这些方法调用进行拦截,这些拦截为目标调用的功能增强提供了工作空间。拦截过程在JDK的Proxy代理对象中,是通过invoke方法来完成的,这个invoke方法是虚拟机触发的一个回调;而在CGLIB的Proxy代理对象中,拦截是由设置好的回调callback方法来完成。有了这些拦截器的拦截作用,才会有AOP切面增强大显身手的舞台。

     

      具体来说,在ProxyFactoryBean的回调中,首先会根据配置来对拦截器是否与当前的调用方法相匹配进行判断。如果当前的调用方法与配置的拦截器相匹配,那么相应的拦截器就会开始发挥作用。这个过程是一个遍历的过程,它会遍历在Proxy代理对象中设置的拦截器链中的所有拦截器。经过这个过程后,在代理对象中定义好的拦截器链中的拦截器会被逐一调用,直到整个拦截器的调用完成位置。在对拦截器的调用完成以后,才是对目标对象的方法调用。这样,一个普通的Java对象的功能就得到了增强,这种增强和现有的目标对象的设计是正交解耦的,这也是AOP需要达到的一个目标。


      在拦截器的调用过程中,实际上已经封装了Spring对AOP的实现,比如对各种通知器的增强织入功能。尽管在使用SpringAOP的时候,看到的是一些Advice的使用,但实际上这些AOP应用中接触到的Advice通知是不能直接对目标对象完成增强的。为了完成AOP应用需要的对目标对象的增强,Spring AOP做了许多工作,对应于每种Advice通知,Spring设计了对应的AdviceAdapter通知适配器,这些通知适配器实现了advice通知对目标对象不同增强方式。对于这些AdviceAdapter通知适配器,在AopProxy代理对象的回调方法中,需要由一个注册机制,它们才能发挥作用。完成这个注册过程之后,在拦截器链中运行的拦截器已经是经过这些AdviceAdapter适配过的拦截器了。有了这些拦截器,再去结合AopProxy代理对象的拦截回调机制,才能够让advice通知对目标对象的增强作用是时在在地发生。“谁知盘中餐,粒粒皆辛苦”。
看起来简洁易用地AOP,和IOC容器地实现一样,背后同样蕴含这许多艰辛的努力。



0 0
原创粉丝点击