- Spring技術內幕:深入解析Spring架構與設計原理(第2版)
- 計文柯
- 8706字
- 2018-12-31 19:55:45
3.4 Spring AOP攔截器調用的實現
3.4.1 設計原理
在Spring AOP通過JDK的Proxy方式或CGLIB方式生成代理對象的時候,相關的攔截器已經配置到代理對象中去了,攔截器在代理對象中起作用是通過對這些方法的回調來完成的。
如果使用JDK的Proxy來生成代理對象,那么需要通過InvocationHandler來設置攔截器回調;而如果使用CGLIB來生成代理對象,就需要根據CGLIB的使用要求,通過Dynamic-AdvisedInterceptor來完成回調。關于這兩種方式的攔截過程,下面我們會進行詳細的分析。
3.4.2 JdkDynamicAopProxy的invoke攔截
前面介紹了在Spring中通過ProxyFactoryBean實現AOP功能的第一步、得到AopProxy代理對象的基本過程,以及通過使用JDK和CGLIB最終產生AopProxy代理對象的實現原理。下面來看看AopProxy代理對象的攔截機制是怎樣發揮作用和實現AOP功能的。在JdkDynamicAopProxy中生成Proxy對象時,我們回顧一下它的AopProxy代理對象的生成調用,如下所示:
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
這里的this參數對應的是InvocationHandler對象,InvocationHandler是JDK定義的反射類的一個接口,這個接口定義了invoke方法,而這個invoke方法是作為JDK Proxy代理對象進行攔截的回調入口出現的。在JdkDynamicAopProxy中實現了InvocationHandler接口,也就是說當Proxy對象的代理方法被調用時,JdkDynamicAopProxy的invoke方法作為Proxy對象的回調函數被觸發,從而通過invoke的具體實現,來完成對目標對象方法調用的攔截或者說功能增強的工作。JdkDynamicAopProxy的invoke方法實現如代碼清單3-18所示。從代碼清單中可以看到,對Proxy對象的代理設置是在invoke方法中完成的,這些設置包括獲取目標對象、攔截器鏈,同時把這些對象作為輸入,創建了ReflectiveMethodInvocation對象,通過這個ReflectiveMethodInvocation對象來完成對AOP功能實現的封裝。在這個invoke方法中,包含了一個完整的攔截器鏈對目標對象的攔截過程,比如獲得攔截器鏈并對攔截器鏈中的攔截器進行配置,逐個運行攔截器鏈里的攔截增強,直到最后對目標對象方法的運行等。
代碼清單3-18 AopProxy代理對象的回調
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation = null; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { //如果目標對象沒有實現Object類的基本方法:equals return equals(args[0]); } if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { //如果目標對象沒有實現Object類的基本方法:hashCode return hashCode(); } if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { //根據代理對象的配置來調用服務 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal = null; if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } //得到目標對象的地方 target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } // 這里獲得定義好的攔截器鏈 List<Object> chain = this.advised.getInterceptorsAndDynamicInterception Advice(method, targetClass); // 如果沒有設定攔截器,那么就直接調用target的對應方法 if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { // 如果有攔截器的設定,那么需要調用攔截器之后才調用目標對象的相應方法 //通過構造一個ReflectiveMethodInvocation來實現,下面會看 //這個ReflectiveMethodInvocation類的具體實現 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); //沿著攔截器鏈繼續前進 retVal = invocation.proceed(); } if (retVal != null && retVal = = target && method.getReturnType().isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
3.4.3 Cglib2AopProxy的intercept攔截
在分析Cglib2AopProxy的AopProxy代理對象生成的時候,我們了解到對于AOP的攔截調用,其回調是在DynamicAdvisedInterceptor對象中實現的,這個回調的實現在intercept方法中,如代碼清單3-19所示。Cglib2AopProxy的intercept回調方法的實現和JdkDynamic-AopProxy的回調實現是非常類似的,只是在Cglib2AopProxy中構造CglibMethodInvocation對象來完成攔截器鏈的調用,而在JdkDynamicAopProxy中是通過構造ReflectiveMethod-Invocation對象來完成這個功能的。
代碼清單3-19 DynamicAdvisedInterceptor的intercept
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Class targetClass = null; Object target = null; try { if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } target = getTarget(); if (target != null) { targetClass = target.getClass(); } //從advised中取得配置好的AOP通知 List<Object> chain = this.advised.getInterceptors AndDynamicInterceptionAdvice(method, targetClass); Object retVal = null; // 如果沒有AOP通知配置,那么直接調用target對象的調用方法 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { retVal = methodProxy.invoke(target, args); } else { //通過CglibMethodInvocation來啟動advice通知 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal); return retVal; } finally { if (target != null) { releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
3.4.4 目標對象方法的調用
如果沒有設置攔截器,那么會對目標對象的方法直接進行調用。對于JdkDynamic-AopProxy代理對象,這個對目標對象的方法調用是通過AopUtils使用反射機制在AopUtils.invokeJoinpointUsingReflection的方法中實現的,如代碼清單3-20所示。在這個調用中,首先得到調用方法的反射對象,然后使用invoke啟動對方法反射對象的調用。
代碼清單3-20 使用反射完成目標對象的方法調用
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable { // 這里是使用反射調用target對象方法的地方 try { ReflectionUtils.makeAccessible(method); return method.invoke(target, args); } catch (InvocationTargetException ex) { //拋出AOP異常,對異常進行轉換 throw ex.getTargetException(); } catch (IllegalArgumentException ex) { throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex); } catch (IllegalAccessException ex) { throw new AopInvocationException("Could not access method [" + method + "]", ex); } }
對于使用Cglib2AopProxy的代理對象,它對目標對象的調用是通過CGLIB的MethodProxy對象來直接完成的,這個對象的使用是由CGLIB的設計決定的。具體的調用在DynamicAdvisedInterceptor的intercept方法中可以看到,使用的是CGLIB封裝好的功能,相對JdkDynamicAopProxy的實現來說,形式上看起來較為簡單,但它們的功能卻是一樣的,都是完成對目標對象方法的調用,具體的代碼實現如下:
retVal = methodProxy.invoke(target, args);
3.4.5 AOP攔截器鏈的調用
在了解了對目標對象的直接調用以后,開始進入AOP實現的核心部分了,AOP是怎樣完成對目標對象的增強的?這些實現封裝在AOP攔截器鏈中,由一個個具體的攔截器來完成。
前面介紹了使用JDK和CGLIB會生成不同的AopProxy代理對象,從而構造了不同的回調方法來啟動對攔截器鏈的調用,比如在JdkDynamicAopProxy中的invoke方法,以及在Cglib2AopProxy中使用DynamicAdvisedInterceptor的intercept方法。雖然它們使用了不同的AopProxy代理對象,但最終對AOP攔截的處理可謂殊途同歸:它們對攔截器鏈的調用都是在ReflectiveMethodInvocation中通過proceed方法實現的。在proceed方法中,會逐個運行攔截器的攔截方法。在運行攔截器的攔截方法之前,需要對代理方法完成一個匹配判斷,通過這個匹配判斷來決定攔截器是否滿足切面增強的要求。大家一定還記得前面提到的,在Pointcut切點中需要進行matches的匹配過程,即matches調用對方法進行匹配判斷,來決定是否需要實行通知增強。以下看到的調用就是進行matches的地方,具體的處理過程在ReflectiveMethodInvocation的proceed方法中,如代碼清單3-21所示。在proceed方法中,先進行判斷,如果現在已經運行到攔截器鏈的末尾,那么就會直接調用目標對象的實現方法;否則,沿著攔截器鏈繼續進行,得到下一個攔截器,通過這個攔截器進行matches判斷,判斷是否是適用于橫切增強的場合,如果是,從攔截器中得到通知器,并啟動通知器的invoke方法進行切面增強。在這個過程結束以后,會迭代調用proceed方法,直到攔截器鏈中的攔截器都完成以上的攔截過程為止。
代碼清單3-21 攔截器的運行
public Object proceed() throws Throwable { //從索引為-1的攔截器開始調用,并按序遞增 //如果攔截器鏈中的攔截器迭代調用完畢,這里開始調用target的函數,這個函數是通過 //反射機制完成的,具體實現在AopUtils.invokeJoinpointUsingReflection方法中 if (this.currentInterceptorIndex == this.interceptorsAndDynamic- MethodMatchers.size() -1) { return invokeJoinpoint(); } //這里沿著定義好的 interceptorOrInterceptionAdvice鏈進行處理 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { //這里對攔截器進行動態匹配的判斷,還記得前面分析的Pointcut嗎?這里是 //觸發進行匹配的地方,如果和定義的Pointcut匹配,那么這個advice將會得到執行 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { //如果不匹配,那么proceed會被遞歸調用,直到所有的攔截器都被運行過為止 return proceed(); } } else { //如果是一個interceptor,直接調用這個interceptor對應的方法 return((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
以上就是整個攔截器及target目標對象方法被調用的過程。“小荷才露尖尖角”,我們已經在這里看到對advice通知的調用入口了,雖然這個大名鼎鼎的advice到現在還沒有完全現身,但已經看到了它的運行軌跡。先提出幾個問題來提提大家的興趣:這些advisor是怎樣從配置文件中獲得,并配置到proxy的攔截器鏈中去的?我們平常使用的advice通知是怎樣起作用的?這些都是了解AOP實現原理的重要問題,下面就這些問題已經展示的線索繼續展開分析,去尋求這些問題的答案。
3.4.6 配置通知器
在整個AopProxy代理對象的攔截回調過程中,先回到ReflectiveMethodInvocation類的proceed方法。在這個方法里,可以看到得到了配置的interceptorOrInterceptionAdvice,如下所示:
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
這個interceptorOrInterceptionAdvice是獲得的攔截器,它通過攔截器機制對目標對象的行為增強起作用。這個攔截器來自interceptorsAndDynamicMethodMatchers,具體來說,它是interceptorsAndDynamicMethodMatchers持有的List中的一個元素。關于如何配置攔截器的問題,就轉化為這個List中的攔截器元素是從哪里來,在哪里配置的問題。接著對invoke調用進行回放,回到JdkDynamicAopProxy中的invoke方法中,可以看到這個List中的interceptors是在哪個調用中獲取的。對于Cglib2AopProxy,也有類似的過程,只不過這個過程是在DynamicAdvisedInterceptor的intercept回調中實現的,如下所示:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
在上面的代碼中可以看到,獲取interceptors的操作是由advised對象完成的,這個advised是一個AdvisedSupport對象,從類的繼承關系上看,這個AdvisedSupport類同時也是ProxyFactoryBean的基類。從AdvisedSupport的代碼中可以看到getInterceptorsAnd-DynamicInterceptionAdvice的實現,如代碼清單3-22所示。在這個方法中取得了攔截器鏈,在取得攔截器鏈的時候,為提高取得攔截器鏈的效率,還為這個攔截器鏈設置了緩存。
代碼清單3-22 AdvisedSupport取得攔截器
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { //這里使用了cache,利用cache去獲取已有的inteceptor鏈,但是第一次還是需要自己 //動手生成的。這個inteceptor鏈的生成是由 advisorChainFactory完成的, //在這里使用的是DefaultAdvisorChainFactory MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
取得攔截器鏈的工作是由配置好的advisorChainFactory來完成的,從名字上可以猜到,它是一個生成通知器鏈的工廠。在這里,advisorChainFactory被配置成一個DefaultAdvisorChainFactory對象,在DefaultAdvisorChainFactory中實現了interceptor鏈的獲取過程,如代碼清單3-23所示。在這個獲取過程中,首先設置了一個List,其長度是由配置的通知器的個數來決定的,這個配置就是在XML中對ProxyFactoryBean做的interceptNames屬性的配置。然后,DefaultAdvisorChainFactory會通過一個AdvisorAdapterRegistry來實現攔截器的注冊,AdvisorAdapterRegistry對advice通知的織入功能起了很大的作用,關于AdvisorAdapterRegistry對象的實現原理,會在后面分析通知是如何實現增強的部分進行闡述。有了AdvisorAdapterRegistry注冊器,利用它來對從ProxyFactoryBean配置中得到的通知進行適配,從而獲得相應的攔截器,再把它加入前面設置好的List中去,完成所謂的攔截器注冊過程。在攔截器適配和注冊過程完成以后,List中的攔截器會被JDK生成的AopProxy代理對象的invoke方法或者CGLIB代理對象的intercept攔截方法取得,并啟動攔截器的invoke調用,最終觸發通知的切面增強。
代碼清單3-23 DefaultAdvisorChainFactory生成攔截器鏈
public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, Class targetClass) { //advisor鏈已經在config中持有了,這里可以直接使用 List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); boolean hasIntroductions = hasMatchingIntroductions(config, targetClass); AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut(). getClassFilter().matches(targetClass)) { //攔截器鏈是通過AdvisorAdapterRegistry來加入的,這個AdvisorAdapterRegistry //對advice織入起了很大的作用,在后面的分析中會看到 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); //使用MethodMatchers的matches方法進行匹配判斷 if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { if (mm.isRuntime()) { for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamic MethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList (interceptors)); } } } } else if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } //判斷Advisors是否符合配置要求 private static boolean hasMatchingIntroductions(Advised config, Class targetClass) { for (int i = 0; i < config.getAdvisors().length; i++) { Advisor advisor = config.getAdvisors()[i]; if (advisor instanceof IntroductionAdvisor) { IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter().matches(targetClass)) { return true; } } } return false; }
事實上,這里的advisor通知器是從AdvisorSupport中取得的,從對它的調用過程來看會非常清楚,如圖3-16所示。

圖3-16 Advisor的調用過程
在ProxyFactoryBean的getObject方法中對advisor進行初始化時,從XML配置中獲取了advisor通知器。在ProxyFactoryBean中,對advisor進行初始化的代碼實現如代碼清單3-24所示。在這個初始化的advisor中,可以看到對IoC容器的一個getBean回調,通過對這個IoC容器的getBean調用來得到配置好的advisor通知器。
代碼清單3-24 在攔截器鏈的初始化中獲取advisor通知器
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)); } 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"); } 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 { //需要對Bean的類型進行判斷,是單件類型還是prototype類型 Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { //這里是取得advisor的地方,是通過beanFactory取得的, //把interceptorNames這個List中的interceptor名字 //交給beanFactory,然后通過調用BeanFactory的getBean去獲取 advice = this.beanFactory.getBean(name); } else { //如果Bean的類型是prototype類型 advice = new PrototypePlaceholderAdvisor(name); } addAdvisorOnChainCreation(advice, name); } } } this.advisorChainInitialized = true; }
advisor通知器的取得是委托給IoC容器完成的,但是在ProxyFactoryBean中是如何獲得IoC容器,然后通過回調IoC容器的getBean方法來得到需要的通知器advisor的呢?這涉及IoC容器實現原理,在使用DefaultListableBeanFactory作為IoC容器的時候,它的基類是AbstractAutowireCapableBeanFactory,在這個基類中可以看到一個對Bean進行初始化的initializeBean方法。在這個Bean的初始化過程中,對IoC容器在Bean中的回調進行了設置。這個設置很簡單,首先,判斷這個Bean的類型是不是實現了BeanFactoryAware接口,如果是,那么它一定實現了BeanFactoryAware定義的接口方法,通過這個接口方法,可以把IoC容器設置到Bean自身定義的一個屬性中去。這樣,在這個Bean的自身實現中,就能夠得到它所在的IoC容器,從而調用IoC容器的getBean方法,完成對IoC容器的回調,就像一個有特異功能的Bean一樣,除了使用為自己設計的功能之外,還可以去調用它所在的容器的功能,如下所示:
if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(this); }
對于IoC容器的使用,如果需要回調容器,前提是當前的Bean需要實現BeanFactory-Aware接口,這個接口只需要實現一個接口方法setBeanFactory,同時設置一個屬性來持有BeanFactory的IoC容器,就可以在Bean中取得IoC容器進行回調了。在IoC容器對Bean進行初始化的時候,會對Bean的類型進行判斷,如果這是一個BeanFactoryAware的Bean類型,那么IoC容器會調用這個Bean的setBeanFactory方法,完成對這個BeanFactory在Bean中的設置。具體來說,ProxyFactoryBean實現了這個接口,所以在它的初始化完成以后,可以在Bean中使用容器進行回調。這里設置的this對象,就是Bean所在的IoC容器,一般是DefaultListableBeanFactory對象。在得到這個設置好的BeanFactory以后,ProxyFactoryBean就可以通過回調容器的getBean去獲取配置在Bean定義文件中的通知器了,獲取通知器就是向IoC容器回調getBean的過程。了解IoC容器實現原理的讀者都知道,這個getBean是IoC容器一個非常基本的方法。在調用時,ProxyFactoryBean需要給出通知器的名字,而這些名字都是在interceptorNames的List中已經配置好的,在IoC對FactoryBean進行依賴注入時,會直接注入到FactoryBean的interceptorNames的屬性中。完成這個過程以后,ProxyFactoryBean就獲得了配置的通知器,為完成切面增強做好準備。
3.4.7 Advice通知的實現
經過前面的分析,我們看到在AopProxy代理對象生成時,其攔截器也同樣建立起來了,除此之外,我們還了解了攔截器的攔截調用和最終目標對象的方法調用的實現原理。但是,對于AOP實現的重要部分,Spring AOP定義的通知是怎樣實現對目標對象的增強的呢?本小節將探討這個問題。讀者一定還記得,在為AopProxy代理對象配置攔截器的實現中,有一個取得攔截器的配置過程,這個過程是由DefaultAdvisorChainFactory實現的,而這個工廠類負責生成攔截器鏈,在它的getInterceptorsAndDynamicInterceptionAdvice方法中,有一個適配和注冊過程,在這個適配和注冊過程中,通過配置Spring預先設計好的攔截器,Spring加入了它對AOP實現的處理。為詳細了解這個過程,先從DefaultAdvisorChainFactory的實現開始,如代碼清單3-25所示。可以看到,在DefaultAdvisorChainFactory的實現中,首先構造了一個GlobalAdvisorAdapterRegistry單件,然后,對配置的Advisor通知器進行逐個遍歷,這些通知器鏈都是配置在interceptorNames中的;從getInterceptorsAndDynamicInterceptionAdvice傳遞進來的advised參數對象中,可以方便地取得配置的通知器,有了這些通知器,接著就是一個由GlobalAdvisorAdapterRegistry來完成的攔截器的適配和注冊過程。
代碼清單3-25 DefaultAdvisorChainFactory使用GlobalAdvisorAdapterRegistry得到AOP攔截器
//得到注冊器GlobalAdvisorAdapterRegistry,這是一個單件模式的實現 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut(). getClassFilter().matches(targetClass)) { //從GlobalAdvisorAdapterRegistry中取得MethodInterceptor的實現 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) { if (mm.isRuntime()) { //在getInterceptors()方法中創建新的對象實例 for (MethodInterceptor interceptor : interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher (interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); } } } }
仔細揣摩了以上代碼的讀者一定會注意到,在這個GlobalAdvisorAdapterRegistry中隱藏著不少AOP實現的重要細節,它的getInterceptors方法為AOP實現做出了很大的貢獻,就是這個方法封裝著advice織入實現的入口,我們先從GlobalAdvisorAdapterRegistry的實現入手,如代碼清單3-26所示。從代碼上看,GlobalAdvisorAdapterRegistry的實現很簡潔,起到的基本上是一個適配器的作用,但同時它也是一個單件模式的應用,為Spring AOP模塊提供了一個DefaultAdvisorAdapterRegistry單件,這個DefaultAdvisorAdapterRegistry是下面要分析的重點,像它的名字一樣,由它來完成各種通知的適配和注冊工作。
如圖3-17所示為單件模式的使用,關于單件模式,可以對照Spring的源代碼實現做一個了解。

圖3-17 單件設計模式
代碼清單3-26 GlobalAdvisorAdapterRegistry的實現
public abstract class GlobalAdvisorAdapterRegistry { //單件模式的典型實現,使用靜態類變量來保持一個唯一實例 private static final AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry(); //返回單件DefaultAdvisorAdapterRegistry對象 public static AdvisorAdapterRegistry getInstance() { return instance; } }
從代碼中可以看出,GlobalAdvisorAdapterRegistry是一個標準的單件模式的實現,它配置了一個靜態的final變量instance,這個對象是在加載類的時候就生成的,而且GlobalAdvisorAdapterRegistry還是一個抽象類,不能被實例化,這樣就保證了instance對象的唯一性。在使用這個instance的時候,也是通過一個靜態方法getInstance()來完成的,這樣就保證了這個instance唯一對象的獲取。
到這里,神秘的面紗慢慢地被揭開了,在DefaultAdvisorAdapterRegistry中,設置了一系列的adapter適配器,正是這些adapter適配器的實現,為Spring AOP的advice提供編織能力。下面看一下DefaultAdvisorAdapterRegistry中究竟發生了什么,如代碼清單3-27所示。首先,我們看到了一系列在AOP應用中與用到的Spring AOP的advice通知相對應的adapter適配實現,并看到了對這些adapter的具體使用。具體說來,對它們的使用主要體現在以下兩個方面:一是調用adapter的support方法,通過這個方法來判斷取得的advice屬于什么類型的advice通知,從而根據不同的advice類型來注冊不同的AdviceInterceptor,也就是前面看到的那些攔截器;另一方面,這些AdviceInterceptor都是Spring AOP框架設計好了的,是為實現不同的advice功能提供服務的。有了這些AdviceInterceptor,可以方便地使用由Spring提供的各種不同的advice來設計AOP應用。也就是說,正是這些AdviceInterceptor最終實現了advice通知在AopProxy代理對象中的織入功能。
代碼清單3-27 DefaultAdvisorAdapterRegistry的實現
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { //持有一個AdvisorAdapter的List,這個List中的Adapter是與實現 //Spring AOP的advice增強功能相對應的 private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3); //這里把已有的advice實現的Adapter加入進來,有非常 //熟悉的MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice //這些AOP的advice封裝實現 public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); } //這里是在DefaultAdvisorChainFactory中啟動的getInterceptors方法 public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3); //從Advisor通知器配置中取得advice通知 Advice advice = advisor.getAdvice(); //如果通知是MethodInterceptor類型的通知,直接加入interceptors的 //List中,不需要適配 if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } //對通知進行適配,使用已經配置好的Adapter:MethodBeforeAdviceAdapter、 //AfterReturningAdviceAdapter以及ThrowsAdviceAdapter, //然后從對應的adapter中取出封裝好AOP編織功能的攔截器 for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]); } public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); } }
在了解這些adapter實現之前,先復習一下adapter模式,如圖3-18所示。與源代碼實現進行對比,大家的理解會更加深刻,也不難在其實現中找到對應關系,從名字上就可以看到一系列的adapter,同樣,adaptee就是一系列的advice。

圖3-18 adapter模式
剝繭抽絲,繼續看這些adapter,在DefaultAdvisorAdapterRegistry的getInterceptors調用中,從MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter以及Throws-AdviceAdapter這幾個通知適配器的名字上可以看到,它們完全和advice一一對應,在這里,它們作為適配器被加入到adaper的List中。換一個角度,從這幾個類的設計層次和關系上看,它們都是實現AdvisorAdapter接口的同一層次的類,只是各自承擔著不同的適配任務,一對一地服務于不同的advice實現,如圖3-19所示。

圖3-19 AdvisorAdapter接口中類的設計層次和關系
從源代碼實現的角度,這個類層次實現如圖3-20所示。

圖3-20 AdvisorAdapter接口及其實現
以MethodBeforeAdviceAdapter為例,它的具體實現如代碼清單3-28所示。這個MethodBeforeAdviceAdapter的實現并不復雜,它實現了AdvisorAdapter的兩個接口方法:一個是supportsAdvice,這個方法對advice的類型進行判斷,如果advice是MethodBeforeAdvice的實例,那么返回值為true;另一個是對getInterceptor接口方法的實現,這個方法把advice通知從通知器中取出,然后創建一個MethodBeforeAdviceInterceptor對象,通過這個對象把取得的advice通知包裝起來,然后返回。
代碼清單3-28 MethodBeforeAdviceAdapter的實現
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) { return (advice instanceof MethodBeforeAdvice); } public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); return new MethodBeforeAdviceInterceptor(advice); } }
到這里就非常清楚了,Spring AOP為了實現advice的織入,設計了特定的攔截器對這些功能進行了封裝。雖然應用不會直接用到這些攔截器,但卻是advice發揮作用必不可少的準備。接著這條線索,還是以MethodBeforeAdviceInterceptor為例,看看它是怎樣完成advice的封裝的,如代碼清單3-29所示。MethodBeforeAdviceInterceptor完成的是對MethodBeforeAdvice通知的封裝,可以在MethodBeforeAdviceInterceptor設計的invoke回調方法中,看到首先觸發了advice的before回調,然后才是MethodInvocation的proceed方法調用。看到這里,就已經和前面在ReflectiveMethodInvocation的proceed分析中聯系起來了。回憶一下,在AopProxy代理對象觸發的ReflectiveMethodInvocation的proceed方法中,在取得攔截器以后,啟動了對攔截器invoke方法的調用。按照AOP的配置規則,ReflectiveMethodInvocation觸發的攔截器invoke方法,最終會根據不同的advice類型,觸發Spring對不同的advice的攔截器封裝,比如對MethodBeforeAdvice,最終會觸發MethodBeforeAdviceInterceptor的invoke方法。在MethodBeforeAdviceInterceptor方法中,會先調用advice的before方法,這就是MethodBeforeAdvice所需要的對目標對象的增強效果:在方法調用之前完成通知增強。
代碼清單3-29 MethodBeforeAdviceInterceptor的實現
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable { private MethodBeforeAdvice advice; //為指定的Advice創建對應的MethodBeforeAdviceInterceptor對象 public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } //這個invoke方法是攔截器的回調方法,會在代理對象的方法被調用時觸發回調 public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); return mi.proceed(); } }
了解了MethodBeforeAdviceInterceptor的實現原理,對于其他的advice通知的實現也可以舉一反三,比如AfterReturningAdviceInterceptor的實現,它和MethodBeforeAdviceInterceptor實現不同的地方,就是在AfterReturningAdviceInterceptor的invoke方法中,先完成了MethodInvocation的proceed調用,也就是目標對象的方法調用,然后再啟動advice通知的afterReturning回調,這些實現原理在代碼中可以很清楚地看到,如代碼清單3-30所示。
代碼清單3-30 AfterReturningAdviceInterceptor的實現
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; //為指定的advice創建AfterReturningAdviceInterceptor 對象 public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; } }
ThrowsAdvice的實現,和上面兩種情況非常類似,也是封裝在對應的AdviceInterceptor中實現的,如代碼清單3-31所示,只是相對于MethodBeforeAdvice和AfterReturningAdvice的回調方法調用,ThrowsAdvice的回調方法調用要復雜一些,它維護了一個exceptionHandlerMap來對應不同的方法調用場景,這個exceptionHandlerMap中handler的取得是與觸發ThrowsAdvice增強的異常相關的。
代碼清單3-31 ThrowsAdviceInterceptor的實現
public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice { private static final String AFTER_THROWING = "afterThrowing"; private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class); private final Object throwsAdvice; private final Map<Class, Method> exceptionHandlerMap = new HashMap<Class, Method>(); public ThrowsAdviceInterceptor(Object throwsAdvice) { Assert.notNull(throwsAdvice, "Advice must not be null"); this.throwsAdvice = throwsAdvice; //配置ThrowsAdvice的回調方法 Method[] methods = throwsAdvice.getClass().getMethods(); for (Method method : methods) { if (method.getName().equals(AFTER_THROWING) && (method.getParameterTypes().length == 1 || method. getParameterTypes().length == 4) && Throwable.class.isAssignableFrom(method.getParameterTypes() [method.getParameterTypes().length -1]) ) { //配置異常處理 this.exceptionHandlerMap.put(method.getParameterTypes() [method.getParameterTypes().length -1], method); if (logger.isDebugEnabled()) { logger.debug("Found exception handler method: " + method); } } } if (this.exceptionHandlerMap.isEmpty()) { throw new IllegalArgumentException( "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]"); } } public int getHandlerMethodCount() { return this.exceptionHandlerMap.size(); } private Method getExceptionHandler(Throwable exception) { Class exceptionClass = exception.getClass(); if (logger.isTraceEnabled()) { logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]"); } Method handler = this.exceptionHandlerMap.get(exceptionClass); while (handler == null && !exceptionClass.equals(Throwable.class)) { exceptionClass = exceptionClass.getSuperclass(); handler = this.exceptionHandlerMap.get(exceptionClass); } if (handler != null && logger.isDebugEnabled()) { logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler); } return handler; } public Object invoke(MethodInvocation mi) throws Throwable { //把對目標對象的方法調用放入try/catch中,并在catch中觸發 //ThrowsAdvice的回調, //把異常接著向外拋出,不做過多的處理 try { return mi.proceed(); } catch (Throwable ex) { Method handlerMethod = getExceptionHandler(ex); if (handlerMethod != null) { invokeHandlerMethod(mi, ex, handlerMethod); } throw ex; } } //通過反射啟動對ThrowsAdvice回調方法的調用 private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable { Object[] handlerArgs; if (method.getParameterTypes().length == 1) { handlerArgs = new Object[] { ex }; } else { handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex}; } try { method.invoke(this.throwsAdvice, handlerArgs); } catch (InvocationTargetException targetEx) { throw targetEx.getTargetException(); } } }
3.4.8 ProxyFactory實現AOP
在前面的分析中,我們了解了以ProxyFactoryBean為例Spring AOP的實現線索。回到前面提到的Spring AOP的類層次關系,從中看到,除了使用ProxyFactoryBean實現AOP應用之外,還可以使用ProxyFactory來實現Spring AOP的功能,只是在使用ProxyFactory的時候,需要編程式地完成AOP應用的設置。下面舉一個使用ProxyFactory的例子,如代碼清單3-32所示。
代碼清單3-32 ProxyFactory的使用
TargetImpl target = new TargetImpl(); ProxyFactory aopFactory = new ProxyFactory(target); aopFactory.addAdvisor(yourAdvisor); aopFactory.addAdvice(yourAdvice); TargetImpl targetProxy = (TargetImpl)aopFactory.getProxy();
對于使用ProxyFactory實現AOP功能,其實現原理與ProxyFactoryBean的實現原理是一樣的,只是在最外層的表現形式上有所不同。ProxyFactory沒有使用FactoryBean的IoC封裝,而是通過直接繼承ProxyCreatorSupport的功能來完成AOP的屬性配置。至于其他ProxyCreatorSupport的子類,ProxyFactory取得AopProxy代理對象其實是和ProxyFactoryBean一樣的,一般來說,也是以getProxy為入口,由DefaultAopProxyFactory來完成的。關于取得AopProxy的詳細分析和以后對攔截器調用的實現原理,前面都分析過了,這里不再重復。對ProxyFactory實現感興趣的讀者,可以從代碼清單3-33中看到它與ProxyFactoryBean實現上不同的地方。從代碼清單中可以看到,由ProxyFactory的getProxy方法取得AopProxy代理對象,getProxy方法的實現使用了ProxyFactory的基類ProxyCreator-Support的createProxy方法來生成AopProxy代理對象,而AopProxy代理對象的生成是由AopProxyFactory來完成的,它會生成JDK或者CGLIB的代理對象。從這里的getProxy的實現開始,ProxyFactory和ProxyFactoryBean在AOP的功能實現上,包括以后攔截器的調用等,基本上都是一樣的。
代碼清單3-33 ProxyFactory的實現
public class ProxyFactory extends ProxyCreatorSupport { public ProxyFactory() { } public ProxyFactory(Object target) { Assert.notNull(target, "Target object must not be null"); setInterfaces(ClassUtils.getAllInterfaces(target)); setTarget(target); } public ProxyFactory(Class[] proxyInterfaces) { setInterfaces(proxyInterfaces); } public ProxyFactory(Class proxyInterface, Interceptor interceptor) { addInterface(proxyInterface); addAdvice(interceptor); } public ProxyFactory(Class proxyInterface, TargetSource targetSource) { addInterface(proxyInterface); setTargetSource(targetSource); } public <T> T getProxy() { return (T) createAopProxy().getProxy(); } public <T> T getProxy(ClassLoader classLoader) { return (T) createAopProxy().getProxy(classLoader); } public static Object getProxy(Class proxyInterface, Interceptor interceptor) { return new ProxyFactory(proxyInterface, interceptor).getProxy(); } public static Object getProxy(Class proxyInterface, TargetSource targetSource) { return new ProxyFactory(proxyInterface, targetSource).getProxy(); } public static Object getProxy(TargetSource targetSource) { if (targetSource.getTargetClass() == null) { throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class"); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTargetSource(targetSource); proxyFactory.setProxyTargetClass(true); return proxyFactory.getProxy(); } }
- Instant Testing with CasperJS
- Docker技術入門與實戰(第3版)
- Visual Basic 6.0程序設計計算機組裝與維修
- 新編Premiere Pro CC從入門到精通
- Python神經網絡項目實戰
- 小學生C++創意編程(視頻教學版)
- Learning JavaScript Data Structures and Algorithms
- 基于ARM Cortex-M4F內核的MSP432 MCU開發實踐
- Emgu CV Essentials
- Java高級程序設計
- 虛擬現實建模與編程(SketchUp+OSG開發技術)
- Building Web and Mobile ArcGIS Server Applications with JavaScript(Second Edition)
- Build Your Own PaaS with Docker
- Python程序員面試算法寶典
- Swift從入門到精通 (移動開發叢書)