程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Spring源代碼解析(七):Spring AOP中對攔截器調用的實現

Spring源代碼解析(七):Spring AOP中對攔截器調用的實現

編輯:關於JAVA

前面我們分析了Spring AOP實現中得到Proxy對象的過程,下面我們看看在Spring AOP 中攔截器鏈是怎樣被調用的,也就是Proxy模式是怎樣起作用的,或者說Spring是怎樣為 我們提供AOP功能的;

在JdkDynamicAopProxy中生成Proxy對象的時候:

Java代碼

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

這裡的this參數對應的是InvocationHandler對象,這裡我們的JdkDynamicAopProxy實 現了這個接口,也就是說當Proxy對象的函數被調用的時候,這個InvocationHandler的 invoke方法會被作為回調函數調用,下面我們看看這個方法的實現:

Java代碼

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 {
       // Try special rules for equals() method and implementation of the
       // Advised AOP configuration interface.
       if (!this.equalsDefined && AopUtils.isEqualsMethod (method)) {
         // What if equals throws exception!?
         // This class implements the equals(Object) method itself.
         return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;
       }
       if (!this.hashCodeDefined && AopUtils.isHashCodeMethod (method)) {
         // This class implements the hashCode() method itself.
         return new Integer(hashCode());
       }
       if (Advised.class == method.getDeclaringClass()) {
         // service invocations on ProxyConfig with the proxy config
         return AopUtils.invokeJoinpointUsingReflection (this.advised, method, args);
       }
       Object retVal = null;
       if (this.advised.exposeProxy) {
         // make invocation available if necessary
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
       }
       // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
       // in case it comes from a pool.
       // 這裡是得到目標對象的地方,當然這個目標對象可能來自於一個實例 池或者是一個簡單的JAVA對象
       target = targetSource.getTarget();
       if (target != null) {
         targetClass = target.getClass();
       }
       // get the interception chain for this method
       // 這裡獲得定義好的攔截器鏈
       List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice (
           this.advised, proxy, method, targetClass);
       // Check whether we have any advice. If we don't, we can fallback on direct
       // reflective invocation of the target, and avoid creating a MethodInvocation.
       // 如果沒有設定攔截器,那麼我們就直接調用目標的對應方法
       if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
       }
       else {
         // We need to create a method invocation...
         // invocation = advised.getMethodInvocationFactory ().getMethodInvocation(
         //     proxy, method, targetClass, target, args, chain, advised);
         // 如果有攔截器的設定,那麼需要調用攔截器之後才調用目標對象 的相應方法
         // 這裡通過構造一個ReflectiveMethodInvocation來實現,下面我 們會看這個ReflectiveMethodInvocation類
         invocation = new ReflectiveMethodInvocation(
             proxy, target, method, args, targetClass, chain);
         // proceed to the joinpoint through the interceptor chain
         // 這裡通過ReflectiveMethodInvocation來調用攔截器鏈和相應的 目標方法
         retVal = invocation.proceed();
       }
       // massage return value if necessary
       if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {
         // Special case: it returned "this" and the return type of the method is type-compatible
         // Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
       }
       return retVal;
     }
     finally {
       if (target != null && !targetSource.isStatic()) {
         // must have come from TargetSource
         targetSource.releaseTarget(target);
       }
       if (setProxyContext) {
         // restore old proxy
         AopContext.setCurrentProxy(oldProxy);
       }
     }
   }

我們先看看目標對象方法的調用,這裡是通過AopUtils的方法調用 - 使用反射機制來 對目標對象的方法進行調用:

Java代碼

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
     throws Throwable {
     // Use reflection to invoke the method.
     // 利用放射機制得到相應的方法,並且調用invoke
     try {
       if (!Modifier.isPublic(method.getModifiers()) ||
           !Modifier.isPublic(method.getDeclaringClass ().getModifiers())) {
         method.setAccessible(true);
       }
       return method.invoke(target, args);
     }
     catch (InvocationTargetException ex) {
       // Invoked method threw a checked exception.
       // We must rethrow it. The client won't see the interceptor.
       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("Couldn't access method: " + method, ex);
     }
   }

對攔截器鏈的調用處理是在ReflectiveMethodInvocation裡實現的:

Java代碼

public Object proceed() throws Throwable {
     //  We start with an index of -1 and increment early.
     // 這裡直接調用目標對象的方法,沒有攔截器的調用或者攔截器已經調用完 了,這個currentInterceptorIndex的初始值是0
     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {
       return invokeJoinpoint();
     }
     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.
       // 這裡獲得相應的攔截器,如果攔截器可以匹配的上的話,那就調用攔 截器的invoke方法
       InterceptorAndDynamicMethodMatcher dm =
         (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
       if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(nextInvocation());
       }
       else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         // 如果攔截器匹配不上,那就調用下一個攔截器,這個時候攔截器 鏈的位置指示後移並迭代調用當前的proceed方法
         this.currentInterceptorIndex++;
         return proceed();
       }
     }
     else {
       // It's an interceptor, so we just invoke it: The pointcut will have
       // been evaluated statically before this object was constructed.
       return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());
     }
   }

這裡把當前的攔截器鏈以及在攔截器鏈的位置標志都clone到一個MethodInvocation對 象了,作用是當前的攔截器執行完之後,會繼續沿著得到這個攔截器鏈執行下面的攔截行 為,也就是會迭代的調用上面這個proceed:

Java代碼

private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {
     ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();
     invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;
     invocation.parent = this;
     return invocation;
   }

這裡的nextInvocation就已經包含了當前的攔截鏈的基本信息,我們看到在 Interceptor中的實現比如TransactionInterceptor的實現中:

Java代碼

public Object invoke(final MethodInvocation invocation) throws Throwable {
    ......//這裡是TransactionInterceptor插入的事務處理代碼,我們會在後面 分析事務處理實現的時候進行分析
       try {
         //這裡是對配置的攔截器鏈進行迭代處理的調用
         retVal = invocation.proceed();
       }
    ......//省略了和事務處理的異常處理代碼 ,也是TransactionInterceptor插 入的處理
      else {
       try {
         Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager ()).execute(txAttr,
             new TransactionCallback() {
               public Object doInTransaction(TransactionStatus status) {
                 //這裡是TransactionInterceptor插入對事務處 理的代碼
                 TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);
                 //這裡是對配置的攔截器鏈進行迭代處理的調用 ,接著順著攔截器進行處理
                 try {
                   return invocation.proceed();
                 }
    ......//省略了和事務處理的異常處理代碼 ,也是TransactionInterceptor插 入的處理
    }

從上面的分析我們看到了Spring AOP的基本實現,比如Spring怎樣得到Proxy,怎樣利 用JAVA Proxy以及反射機制對用戶定義的攔截器鏈進行處理。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved