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
未完待續……