zoukankan      html  css  js  c++  java
  • Spring技术内幕:Spring AOP的实现原理(二)

    **二、AOP的设计与实现
    1、JVM的动态代理特性**
    在Spring AOP实现中, 使用的核心技术时动态代理。而这样的动态代理实际上是JDK的一个特性。通过JDK的动态代理特性,能够为随意Java对象创建代理对象,对于详细使用来说,这个特性使通过Java Reflection API来完毕的。在此之前先简要复习一下Proxy模式。其静态类图例如以下:
    这里写图片描写叙述
    我们能够看到有一个RealSubject,这个对象是目标对象。而在代理模式的设计中。会设计一个接口和目标对象一致的代理对象Proxy。它们都实现了接口Subject的request方法。在这样的情况下,对目标对象的request调用。往往就被代理对象“浑水摸鱼”给拦截了。通过这样的拦截,为目标对象的方法操作做了铺垫。
    在Proxy的调用过程中。假设客户调用Proxy的request方法。会在调用目标对象的request方法,会在调用目标对象的request方法的前后调用一系列的处理。而这一系列的处理相当于对目标对象来说是透明的。目标对象对这些处理能够毫不知情,这就是proxy模式。


    我们知道JDK中已经实现了这个Proxy模式。在基于Java虚拟机设计应用程序时,仅仅须要直接使用这个特性就能够了。

    详细来说。能够再Java的Reflection包中看到proxy对象,这个对象生成后,所起的作用就相似于Proxy模式中的Proxy对象。

    在使用时,还须要为代理对象设计一个回调方法,这个回调方法起到的作用是,在当中假如了作为代理须要额外处理的动作。这个回调方法。假设在JDK中实现,须要实现以下所看到的的InvocationHandler接口:

    public interface InvocationHandler{
      public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
    }

    至于invoke方法和Proxy挂上钩,熟悉proxy使用方法的读者都知道,仅仅要在实现通过调用Proxy.newInstance方法生成详细的Proxy对象时,把InvocationHandler设置到參数里面就能够了,剩下的由Java虚拟机来完毕。
    2、Spring AOP的设计分析
    Spring AOP以动态代理技术为基础,设计出了一系列AOP的横切实现。比方前置通知、返回通知、异常通知等。同一时候SpringAOP还提供了一系列的Pointcut来匹配切入点。能够使用现有的切入点来设计横切面。也能够扩展相关的Pointcut方法来切入需求。
    在Spring AOP中,尽管对于AOP的使用者来说,仅仅须要配置相关的Bean定义就可以,但细致分析Spring AOP内部设计能够看到,为了让AOP起作用。须要完毕一系列过程。比方,须要为目标对象建立代理对象。这个代理对象能够通过使用JDK的Proxy来完毕,也能够通过第三方的类生成器CGLIB来完毕。然后。还须要启动代理对象的拦截器来完毕各种横切面的织入,这一系列的织入设计是通过一系列Adapter来实现的。

    通过Adapter的设计,能够把AOP的横切面设计和Proxy模式有机结合起来,从而实如今AOP中定义好的各种织入方式。


    3、Spring AOP的应用场景
    SpringAOP把跨越应用程序多个模块的功能抽象出俩,并通过简单的AOP的使用。灵活的编制到模块中,比方能够通过AOP实现应用程序中的日志功能。还有一方面,在Spring内部,一些支持模块也是通过Spring AOP来实现的,比方后面将要介绍的事务处理。以下以ProxyFactoryBean的实现为例,和大家一起来了解Spring AOP的详细设计和实现
    **三、建立AOPProxy代理对象
    1、设计原理**
    在Spring的AOP模块中,一个基本的部分是代理对象的生成,而对于Spring应用,能够看到,是通过配置和调用Spring的ProxyFactoryBean来完毕这个任务的。在ProxyFactoryBean中,封装了主要代理对象的生成过程。

    在这个过程中,能够使用JDK的Proxy和CGLIB两种方式。
    以ProxyFactoryBean的设计为中心。能够看到相关类的继承关系:
    这里写图片描写叙述
    2、配置ProxyFactoryBean
    我们開始进入到Spring AOP的实现部分,在分析Spring AOP的实现原理中。主要以ProxyFactoryBean的实现作为样例和实现的基本线索进行分析。

    这是由于ProxyFactoryBean是在Spring IOC环境中创建AOP应用的底层方法。也是最灵活的方法,Spring通过他完毕了对AOP使用分封装。

    以ProxyFactoryBean的实现为入口。逐层深入。是一条帮助我们高速理解Spring AOP实现的学习路径。
    在了解ProxyFactoryBean的实现之前,先简要介绍下ProxyFactoryBean的配置和使用,在基于XML配置Spring的Bean时,往往须要一系列的配置补助来使用ProxyFactoryBean和AOP。
    1)定义使用的通知器Advisor,这个通知器应该作为一个Bean来定义。

    这个通知器的实现定义了须要对目标对象进行增强的切面行为,也就是Advice通知。


    2)定义ProxyFactoryBean,把他作为还有一个Bean来定义,他是封装AOP功能的主要类。
    3)定义target属性。作为target属性注入的Bean,是须要用AOP通知器中的切面应用来增强的对象,也就是前面提到的base对象。
    有了这些配置,就能够使用ProxyFactoryBean完毕AOP的基本功能了,比如:

    <bean id="testAdvisor" class="com.jader.TestAdvisor" />
    <bean id="testAOP" class="org.springframework.aop.ProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>com.jader.AbcInterface</value>
        </property>
        <property name="interceptorNames">
            <list>
                <value>testAdvisor</value>
            </list>
        </property>
    </bean>

    掌握这些配置信息后,就能够详细看一看这些AOP是如何实现的。也就是说,切面应用是如何通过ProxyFactoryBean对target对象起作用的,以下详细分析。


    3、ProxyFactoryBean生成AOPProxy代理对象
    在Spring AOP的使用中,我们已经知道,能够通过ProxyFactoryBean来配置目标对象和切面行为。这个ProxyFactoryBean是一个FactoryBean。在ProxyFactoryBean中,通过interceptorNames属性来配置已经定义好的通知器Advisor。尽管名字为interceptorNames但实际上却是供AOP应用配置通知器的地方。

    在ProxyFactoryBean中,须要为target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备工作。
    ProxyFactoryBean的AOP实现须要依赖JDK或者CGLIB提供的Proxy特性。从FactoryBean中获取对象。是以getObject方法作为入口完毕的。ProxyFactoryBean实现中的getObject方法。是FactoryBean须要实现的接口。

    对ProxyFactoryBean来说。把须要对target目标对象增加的增强处理都通过getObject方法进行封装了。

    这些增强处理是为AOP功能的实现提供服务的。getObject方法首先对通知器链进行初始化,通知器链封装了一系列的拦截器,这些拦截器从配置中读取。然后为代理对象的生成做好准备。

    在生成代理对象时。由于Spring中有SingleTon类型和prototype相似这两种不同的Bean,所以要对代理对象的生成做一个区分。


    这里写图片描写叙述
    getObject的代码例如以下:

    
        /**
         * Return a proxy. Invoked when clients obtain beans from this factory bean.
         * Create an instance of the AOP proxy to be returned by this factory.
         * The instance will be cached for a singleton, and create on each call to
         * {@code getObject()} for a proxy.
         * @return a fresh AOP proxy reflecting the current state of this factory
         */
        public Object getObject() throws BeansException {
            // 这里初始化通知器链
            initializeAdvisorChain();
            // 这里对SingleTon和prototype的类型进行区分,生成相应的proxy
            if (isSingleton()) {
                return getSingletonInstance();
            }
            else {
                if (this.targetName == null) {
                    logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                            "Enable prototype proxies by setting the 'targetName' property.");
                }
                return newPrototypeInstance();
            }
        }

    为Proxy代理对象配置Advisor链是在initializeAdvisorChain方法中实现的。这个初始化过程中有一个标志位AdvisorChainInitialized。这个标志用来表示通知器是否已经初始化。假设已经初始化。那么这里就会在初始化。而是直接返回。

    也就说,这个初始化的工作发生在应用第一次通过ProxyFactoryBean去获代替理对象的时候。

    在完毕这个初始化之后,接着读取配置中出现的全部通知器,这个取得通知器的过程也比較简单,把通知器的名字交给容器的getBean方法就能够了,这是通过对IOC容器实现的一个回调完毕的。然后把从IOC容器中取得的通知器增加到拦截器链中,这个动作是由addAdvisorOnChainCreation方法来实现的。
    以下看看对Advisor配置链的初始化:

    /**
         * Create the advisor (interceptor) chain. Aadvisors that are sourced
         * from a BeanFactory will be refreshed each time a new prototype instance
         * is added. Interceptors added programmatically through the factory API
         * are unaffected by such changes.
         */
        private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
            if (this.advisorChainInitialized) {
                return;
            }
            if (!ObjectUtils.isEmpty(this.interceptorNames)) {
                if (this.beanFactory == null) {
                    throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                            "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
                }
                // Globals can't be last unless we specified a targetSource using the property...
                if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
                        this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
                    throw new AopConfigException("Target required after globals");
                }
                // Materialize interceptor chain from bean names.
               // 这里是增加Advisor链的调用,是通过interceptorNames属性进行配置
                for (String name : this.interceptorNames) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Configuring advisor or advice '" + name + "'");
                    }
                    if (name.endsWith(GLOBAL_SUFFIX)) {
                        if (!(this.beanFactory instanceof ListableBeanFactory)) {
                            throw new AopConfigException(
                                    "Can only use global advisors or interceptors with a ListableBeanFactory");
                        }
                        addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                                name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                    }
                    else {
                        // If we get here, we need to add a named interceptor.
                        // We must check if it's a singleton or prototype.
                        // 假设程序在这里被调用,那么须要增加命名的拦截器advice,而且须要检查这个Bean是SingleTon还是prototype类型
                        Object advice;
                        if (this.singleton || this.beanFactory.isSingleton(name)) {
                            // Add the real Advisor/Advice to the chain.
                            advice = this.beanFactory.getBean(name);
                        }
                        else {
                            // It's a prototype Advice or Advisor: replace with a prototype.
                            // Avoid unnecessary creation of prototype bean just for advisor chain initialization.
                            advice = new PrototypePlaceholderAdvisor(name);
                        }
                        addAdvisorOnChainCreation(advice, name);
                    }
                }
            }
            this.advisorChainInitialized = true;
        }

    未完待续……

  • 相关阅读:
    Windows 7 SP1无人值守自动应答文件制作
    Ubuntu GNOME单击任务栏图标最小化设置
    NOIP2017题解
    NOIP2017游记
    大模拟1.0
    奇袭
    礼物
    找硬币
    Fiolki
    SQLserver Delete from where 与Oracle delete from where 的差异
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5342439.html
Copyright © 2011-2022 走看看