關(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í)進步