zoukankan      html  css  js  c++  java
  • Spring中的AOP(二)

    2.5 Spring的织入

    在上一篇文章中,我们介绍了Pointcut、Advice、Advisor三个必要模块,剩下的工作就是把它们拼装起来,也就是织入过程。在Spring中,使用类org.springframework.aop.framework.ProxyFactory作为织入器。

    2.5.1 认识ProxyFactory

    首先,ProxyFactory并非Spring AOP中唯一可用的织入器,而是最基本的一个织入器实现。所以,我们就从这个最基本的织入器开始,了解一下织入过程到底是什么样子的。
    使用ProxyFactory进行织入的逻辑很简单,只要为它提供生产代理对象的原材料,它就会返回那个织入完成的代理对象。我们来看示例代码:

        ProxyFactory weaver = new ProxyFactory(yourTargetObject);
        Advisor advisor = ...;
        weaver.addAdvisor(advisor);
        Object proxyObject = weaver.getProxy();
    

    我们知道,Spring AOP在使用代理模式实现AOP的过程中采用了动态代理CGLIB两种机制,分别对某些接口的目标类和没有实现任何接口的目标类进行代理,所以在使用ProxyFactory对目标类进行代理的时候,会通过ProxyFactory的某些行为控制属性对这两种情况进行区分。我们来看具体的场景,首先我们有一个接口,以及它的一个实现类:

    public interface ITask {
        void execute(TaskExecutionContext ctx);
    }
    
    public class MockTask implements ITask {
        public void execute(TaskExecutionContext ctx) {
            System.out.println("task execute.");
        }
    }
    

    另外,我们还需要一个织入到Jointpoint的一个横切逻辑,也就是Advice实现。假设是PerformanceMethodInterceptor

    // 简单的检测系统某些方法的执行性能
    public class PerformanceMethodInterceptor implements MethodInterceptor {
        private final Log logger = LogFactory.getLog(this.getClass());
        public Object invoke(MethodInvocation invocation) throws Throwable {
            StopWatch watch = new StopWatch();
            try {
                watch.start();
                return invocation.proceed();
            } catch (Exception e) {
                //TODO: handle exception
            } finally {
                watch.stop();
                if (logger.isInfoEnabled()) {
                    logger.info(watch.toString());
                }
            }
        }
    }
    
    • 基于接口的代理:MockTask实现了ITask接口,要对这种实现了某些接口的目标类进行代理,我们使用setInterfaces(new Class[]{ITask.class})来明确告知ProxyFactory我们要对ITask接口类型进行代理。
    ProxyFactory weaver = new ProxyFactory(new MockTask);
    weaver.setInterfaces(new Class[]{ITask.class});
    
    • 基于类的代理:如果目标类没有实现任何接口,ProxyFactory会对目标类型进行基于类的代理,即使用CGLIB。假设我们现在有一个对象,定义如下:
    public class Executable {
        public void execute() {
            System.out.println("Executable without any Interfaces");
        }
    }
    

    织入的过程如下所示:

    ProxyFactory weaver = new ProxyFactory(new Executable());
    weaver.addAdvisor(advisor);
    Executable proxyObject = (Executable)weaver.getProxy();
    proxyObject.execute();
    

    但是,即使目标对象类实现了至少一个接口,我们也可以通过proxyTargetClass属性强制ProxyFactory采用基于类的代理。除此之外,如果将ProxyFactoryoptimize属性设为true的话,也会采用基于类的代理机制。

    2.5.2 看清ProxyFactory的本质

    我们不仅要知晓怎么使用ProxyFactory,并且还需要了解它其中的内部实现,这可以帮我们更好地使用它。我们先从它的根说起:

    public interface AopProxy {
        Object getProxy();
        Object getProxy(ClassLoader classLoader)
    }
    

    这个接口对Spring AOP框架内的不同代理实现机制做了适度的抽象,目前,Spring提供了基于JDK动态代理和CGLIB两种机制的AopProxy实现。
    AopProxy相关结构图

    首先,我们来看工厂类AopProxyFactory的定义:

    public interface AopProxyFactory {
        AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
    }
    

    AopProxyFactory的实现类就一个,DefaultAopProxyFactory,它会根据传入的AdvisedSupport示例提供的相关信息,来决定生成什么类型的AopProxy,实现逻辑很简单,伪代码如下:

    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        // 创建Cglib2AopProxy实例,并返回
    } else {
        // 创建JdkDynamicAopProxy实例,并返回
    }
    

    可以发现,生成的AopProxy类型是由AdvisedSupport实例来决定的,我们来看一下这个类到底是何方神圣。
    AdvisedSupport层次结构

    AdvisedSupport继承了ProxyConfig类并实现了Advised接口。我们先来看ProxyConfig类,它其实就是个普通的JavaBean,它定义了5个boolean类型的属性,分别为proxyTargetClass(指定是否使用CGLIB代理)、optimize(告知代理对象是否要进行进一步优化,若为true,则使用CGLIB,默认为false)、opaque(控制代理对象是否可以强制转为Advised类型)、exposeProxyfrozen
    要生成代理对象,光有ProxyConfig提供的控制信息还不够,我们还需要生成代理对象的一些具体信息,比如Jointpoint和Advice,这些信息可以通过实现Advised接口来设置或者查询(addAdvisor()/removeAdvisor())。
    那么,AopProxyAdvisedSupportProxyFactory是什么关系呢?
    ProxyFactory关系

    ProxyFactoryAopProxyAdvisedSupport于一身,所以可以通过它设置生成对象所需要的相关信息,也可以通过它取得最终生成的代理对象。前者是AdvisedSupport的职责,后者是AopProxy的职责。
    至此,我们已经了解了ProxyFactory这个最基本的织入器实现,它还有几个兄弟,比如AspectJProxyFactoryProxyFactoryBean,它们的关系如下所示,在此不作进一步说明,有兴趣的读者可以查阅《Spring揭秘》P179。
    ProxyFactory的兄弟

    参考资料:《Spring揭秘》王福强

  • 相关阅读:
    lazyload is not a function解决方式
    APK反编译(Linux环境下)
    讲解图片压缩的文章
    startActivityForResult相关的
    把APP做成libary的注意事项
    ViewPager+Fragment,Fragment会预加载的问题
    FragmentTabHost使用注意
    使用ReTrofit做缓存(结合上拉加载和下拉刷新)
    极光推送,极光IM使用指南(AndroidStudio)
    AndroidStudio使用注意事项
  • 原文地址:https://www.cnblogs.com/muuu520/p/12852633.html
Copyright © 2011-2022 走看看