1. 程式人生 > >Spring AOP的實現原理(二)

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;
}
  • 1
  • 2
  • 3

至於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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

掌握這些配置資訊後,就可以具體看一看這些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();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

為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;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

未完待續……