深入解析Spring架構(gòu)與設(shè)計原理-AOP

關(guān)于AOP的個人理解

AOP聯(lián)盟定義的AOP體系結(jié)構(gòu)把與AOP相關(guān)的概念大致分為了由高到低、從使用到實現(xiàn)的三個層次。關(guān)于這個體系結(jié)構(gòu),個人的理解是這樣的,從上往下,最高層是語言和開發(fā)環(huán)境,在這個環(huán)境中可以看到幾個重要的概念:base可以視為待增強對象,或者說目標(biāo)對象;aspect指切面,通常包含對于base的增強應(yīng)用;configuration可以看成是一種編織或者說配置,通過在AOP體系中提供這個configuration配置環(huán)境,可以把base和aspect結(jié)合起來,從而完成切面對目標(biāo)對象的編織實現(xiàn)。

對Spring平臺或者說生態(tài)系統(tǒng)來說,AOP是Spring框架的核心功能模塊之一。AOP與IOC容器的結(jié)合使用, 為應(yīng)用開發(fā)或者Spring自身功能的擴展都提供了許多便利。Spring AOP的實現(xiàn)和其他特性的實現(xiàn)一樣,非常豐富,除了可以使用Spring本身提供的AOP實現(xiàn)之外,還封裝了業(yè)界優(yōu)秀的AOP解決方案AspectJ來讓應(yīng)用使用。在這里,主要對Spring自身的AOP實現(xiàn)原理做一些解析;在這個AOP實現(xiàn)中,Spring充分利用了IOC容器Proxy代理對象以及AOP攔截器的功能特性,通過這些對AOP基本功能的封裝機制,為用戶提供了AOP的實現(xiàn)框架。所以,要了解這些AOP的基本實現(xiàn),需要我們對Java 的Proxy機制有一些基本了解。

AOP實現(xiàn)的基本線索

AOP實現(xiàn)中,可以看到三個主要的步驟,一個是代理對象的生成,然后是攔截器的作用,然后是Aspect編織的實現(xiàn)。AOP框架的豐富,很大程度體現(xiàn)在這三個具體實現(xiàn)中,所具有的豐富的技術(shù)選擇,以及如何實現(xiàn)與IOC容器的無縫結(jié)合。畢竟這也是一個非常核心的模塊,需要滿足不同的應(yīng)用需求帶來的解決方案需求。

在Spring AOP的實現(xiàn)原理中,我們主要舉ProxyFactoryBean的實現(xiàn)作為例子和實現(xiàn)的基本線索進行分析;很大一個原因,是因為ProxyFactoryBean是在Spring IoC環(huán)境中,創(chuàng)建AOP應(yīng)用的最底層方法,從中,可以看到一條實現(xiàn)AOP的基本線索。在ProxyFactoryBean中,它的AOP實現(xiàn)需要依賴JDK或者CGLIB提供的Proxy特性。從FactoryBean中獲取對象,是從getObject()方法作為入口完成的。然后為proxy代理對象配置advisor鏈,這個配置是在initializeAdvisorChain方法中完成的;然后就為生成AOP代理對象做好了準(zhǔn)備,生成代理對象如下所示:

private synchronized Object getSingletonInstance() {

? ? if (this.singletonInstance == null) {

? ? ? ? this.targetSource = freshTargetSource();

? ? ? ? if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {

? ? ? ? ? ? // Rely on AOP infrastructure to tell us what interfaces to proxy.?

? ? ? ? ? ? Class targetClass = getTargetClass();

? ? ? ? ? ? if (targetClass == null) {

? ? ? ? ? ? ? ? throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");

? ? ? ? ? ? }

? ? ? ? ? ? // 這里設(shè)置代理對象的接口? ?

? ? ? ? ? ? // setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));?

? ? ? ? }

? ? ? ? // Initialize the shared singleton instance.?

? ? ? ? super.setFrozen(this.freezeProxy);

? ? ? ? // 注意這里的方法會使用ProxyFactory來生成我們需要的Proxy?

? ? ? ? this.singletonInstance = getProxy(createAopProxy());

? ? }

? ? return this.singletonInstance;

}

//使用createAopProxy返回的AopProxy來得到代理對象?

protected Object getProxy(AopProxy aopProxy) {

? ? return aopProxy.getProxy(this.proxyClassLoader);

}

上面我們看到了在Spring中通過ProxyFactoryBean實現(xiàn)AOP功能的第一步,得到AopProxy代理對象的基本過程,下面我們看看AopProxy代理對象的攔截機制是怎樣發(fā)揮作用,是怎樣實現(xiàn)AOP功能的。我們知道,對代理對象的生成,有CGLIB和JDK兩種生成方式,在CGLIB中,對攔截器設(shè)計是通過在Cglib2AopProxy的AopProxy代理對象生成的時候,在回調(diào)DynamicAdvisedInterceptor對象中實現(xiàn)的,這個回調(diào)的實現(xiàn)在intercept方法中完成。對于AOP是怎樣完成對目標(biāo)對象的增強的,這些實現(xiàn)是封裝在AOP攔截器鏈中,由一個個具體的攔截器來完成的。具體攔截器的運行是在以下的代碼實現(xiàn)中完成的,這些調(diào)用在ReflectiveMethodInvocation中。

public Object proceed() throws Throwable {

? ? //? We start with an index of -1 and increment early.?

? ? //如果攔截器鏈中的攔截器迭代調(diào)用完畢,這里開始調(diào)用target的函數(shù),這個函數(shù)是通過反射機制完成的,具體實現(xiàn)在:AopUtils.invokeJoinpointUsingReflection方法里面。?

? ? if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {

? ? ? ? return invokeJoinpoint();

? ? }

? ? //這里沿著定義好的 interceptorOrInterceptionAdvice鏈進行處理。?

? ? Object interceptorOrInterceptionAdvice =

? ? ? ? ? ? this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

? ? if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

? ? ? ? // Evaluate dynamic method matcher here: static part will already have?

? ? ? ? // been evaluated and found to match.?

? ? ? ? //這里對攔截器進行動態(tài)匹配的的判斷,還記得我們前面分析的pointcut嗎?這里是觸發(fā)進行匹配的地方,如果和定義的pointcut匹配,那么這個advice將會得到執(zhí)行。?

? ? ? ? InterceptorAndDynamicMethodMatcher dm =

? ? ? ? ? ? ? ? (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;

? ? ? ? if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {

? ? ? ? ? ? return dm.interceptor.invoke(this);

? ? ? ? } else {

? ? ? ? ? ? // Dynamic matching failed.?

? ? ? ? ? ? // Skip this interceptor and invoke the next in the chain.?

? ? ? ? ? ? // //如果不匹配,那么這個proceed會被遞歸調(diào)用,直到所有的攔截器都被運行過為止。?

? ? ? ? ? ? return proceed();

? ? ? ? }

? ? } else {

? ? ? ? // It's an interceptor, so we just invoke it: The pointcut will have?

? ? ? ? // been evaluated statically before this object was constructed.?

? ? ? ? //如果是一個interceptor,直接調(diào)用這個interceptor對應(yīng)的方法?

? ? ? ? return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

? ? }

}

在調(diào)用攔截器的時候,我們接下去就可以看到對advice的通知的調(diào)用。而經(jīng)過一系列的注冊,適配的過程以后,攔截器在攔截的時候,會調(diào)用到預(yù)置好的一個通知適配器,設(shè)置通知攔截器,這是一系列Spring設(shè)計好為通知服務(wù)的類的一個,是最終完成通知攔截和實現(xiàn)的地方,非常的關(guān)鍵。比如,對MethodBeforeAdviceInterceptor的實現(xiàn)是這樣的:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

? ? private MethodBeforeAdvice advice;

? ? /**

? ? * Create a new MethodBeforeAdviceInterceptor for the given advice.

? ? *

? ? * @param advice the MethodBeforeAdvice to wrap

? ? */

? ? public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {

? ? ? ? Assert.notNull(advice, "Advice must not be null");

? ? ? ? this.advice = advice;

? ? }

? ? //這個invoke方法是攔截器的回調(diào)方法,會在代理對象的方法被調(diào)用的時候觸發(fā)回調(diào)。?

? ? public Object invoke(MethodInvocation mi) throws Throwable {

? ? ? ? this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());

? ? ? ? return mi.proceed();

? ? }

}


在代碼中,可以看到,就是這里,會調(diào)用advice的before方法!這樣就成功的完成了before通知的編織!

因為Spring AOP本身并不打算成為一個一統(tǒng)天下的AOP框架,秉持Spring的一貫設(shè)計理念,設(shè)想中的Spring設(shè)計目標(biāo)應(yīng)該是,致力于AOP框架與IOC容器的緊密集成,通過集成AOP技術(shù)為JavaEE應(yīng)用開發(fā)中遇到的普遍問題提供解決方案,從而為AOP用戶使用AOP技術(shù)提供最大的便利,從這個角度上為Java EE的應(yīng)用開發(fā)人員服務(wù)。在沒有使用第三方AOP解決方案的時候,Spring通過虛擬機的Proxy特性和CGLIB實現(xiàn)了AOP的基本功能,我想,如果有了Spring AOP實現(xiàn)原理的知識背景,再加上我們對源代碼實現(xiàn)的認(rèn)真解讀,可以為我們了解其他AOP框架與IOC容器的集成原理,也打下了很好的基礎(chǔ),并真正了解一個AOP框架是在怎樣實現(xiàn)的。

這還真是就是我們喜歡開源軟件一個原因,有了源代碼,軟件就沒有什么神秘的面紗了!本立而道生,多讀源代碼吧,或者找一本從源代碼出發(fā)講解軟件實現(xiàn)的書來看看,就像以前我們學(xué)習(xí)操作系統(tǒng),學(xué)習(xí)TCP/IP那樣!一定會有長進的。

歡迎工作一到五年的Java工程師朋友們加入Java架構(gòu)開發(fā):855801563

本群提供免費的學(xué)習(xí)指導(dǎo)?架構(gòu)資料?以及免費的解答

不懂得問題都可以在本群提出來?之后還會有職業(yè)生涯規(guī)劃以及面試指導(dǎo)

同時大家可以多多關(guān)注一下小編 純干貨?大家一起學(xué)習(xí)進步

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容