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

Spring源代碼解析(五):Spring AOP獲取Proxy

編輯:關於JAVA

下面我們來看看Spring的AOP的一些相關代碼是怎麼得到Proxy的,讓我們我們先看看 AOP和Spring AOP的一些基本概念:

Advice:

通知,制定在連接點做什麼,在Sping中,他主要描述Spring圍繞方法調用注入的額外 的行為,Spring提供的通知類型有:

before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,這些都是 Spring AOP定義的接口類,具體的動作實現需要用戶程序來完成。

Pointcut:

切點,其決定一個advice應該應用於哪個連接點,也就是需要插入額外處理的地方的 集合,例如,被某個advice作為目標的一組方法。Spring pointcut通常意味著標示方法 ,可以選擇一組方法調用作為pointcut,Spring提供了具體的切點來給用戶使用,比如正 則表達式切點 JdkRegexpMethodPointcut通過正則表達式對方法名進行匹配,其通過使用 AbstractJdkRegexpMethodPointcut中的對MethodMatcher接口的實現來完成pointcut功能 :

Java代碼

public final boolean matches(Method method, Class targetClass) {
     //這裡通過放射得到方法的全名
     String patt = method.getDeclaringClass().getName() + "." + method.getName();
     for (int i = 0; i < this.patterns.length; i++) {
       // 這裡是判斷是否和方法名是否匹配的代碼
       boolean matched = matches(patt, i);
       if (matched) {
         for (int j = 0; j < this.excludedPatterns.length; j++) {
           boolean excluded = matchesExclusion(patt, j);
           if(excluded) {
             return false;
           }
         }
         return true;
       }
     }
     return false;
   }

在JDKRegexpMethodPointcut中通過JDK中的正則表達式匹配來完成pointcut的最終確 定:

Java代碼

protected boolean matches(String pattern, int patternIndex) {
     Matcher matcher = this.compiledPatterns[patternIndex].matcher (pattern);
     return matcher.matches();
   }

Advisor:

當我們完成額外的動作設計(advice)和額外動作插入點的設計(pointcut)以後,我們 需要一個對象把他們結合起來,這就是通知器 - advisor,定義應該在哪裡應用哪個通知 。Advisor的實現有:DefaultPointcutAdvisor他有兩個屬性advice和 pointcut來讓我們 配置advice和pointcut。

接著我們就可以通過ProxyFactoryBean來配置我們的代理對象和方面行為,在 ProxyFactoryBean中有interceptorNames來配置已經定義好的通知器-advisor,雖然這裡 的名字叫做interceptNames,但實際上是供我們配置advisor的地方,具體的代理實現通過 JDK 的Proxy或者CGLIB來完成。因為ProxyFactoryBean是一個FactoryBean,在 ProxyFactoryBean中我們通過getObject()可以直接得到代理對象:

Java代碼

public Object getObject() throws BeansException {
     //這裡初始化通知器鏈
     initializeAdvisorChain();
     if (isSingleton()) {
     //根據定義需要生成單件的Proxy
       return getSingletonInstance();
     }
     else {
     .......
       //這裡根據定義需要生成Prototype類型的Proxy
       return newPrototypeInstance();
     }
   }

我們看看怎樣生成單件的代理對象:

Java代碼

private synchronized Object getSingletonInstance() {
     if (this.singletonInstance == null) {
       this.targetSource = freshTargetSource();
       if (this.autodetectInterfaces && getProxiedInterfaces ().length == 0 && !isProxyTargetClass()) {
         // 這裡設置代理對象的接口
         setInterfaces(ClassUtils.getAllInterfacesForClass (this.targetSource.getTargetClass()));
       }
       // Eagerly initialize the shared singleton instance.
       super.setFrozen(this.freezeProxy);
       // 注意這裡的方法會使用ProxyFactory來生成我們需要的Proxy
       this.singletonInstance = getProxy(createAopProxy());
       // We must listen to superclass advice change events to recache the singleton
       // instance if necessary.
       addListener(this);
     }
     return this.singletonInstance;
   }
   //使用createAopProxy放回的AopProxy來得到代理對象。
   protected Object getProxy(AopProxy aopProxy) {
     return aopProxy.getProxy(this.beanClassLoader);
   }

ProxyFactoryBean的父類是AdvisedSupport,Spring使用AopProxy接口把AOP代理的實 現與框架的其他部分分離開來;在AdvisedSupport中通過這樣的方式來得到AopProxy,當 然這裡需要得到AopProxyFactory的幫助 - 下面我們看到Spring為我們提供的實現,來幫 助我們方便的從JDK或者cglib中得到我們想要的代理對象:

Java代碼

protected synchronized AopProxy createAopProxy() {
     if (!this.isActive) {
       activate();
     }
     return getAopProxyFactory().createAopProxy(this);
   }

而在ProxyConfig中對使用的AopProxyFactory做了定義:

Java代碼

//這個DefaultAopProxyFactory是Spring用來生成AopProxy的地方,
   //當然了它包含JDK和Cglib兩種實現方式。
   private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();

其中在DefaultAopProxyFactory中是這樣生成AopProxy的:

Java代碼

public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
     //首先考慮使用cglib來實現代理對象,當然如果同時目標對象不是接口的實 現類的話
     if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
       advisedSupport.getProxiedInterfaces().length == 0) {
       //這裡判斷如果不存在cglib庫,直接拋出異常。
       if (!cglibAvailable) {
         throw new AopConfigException(
             "Cannot proxy target class because CGLIB2 is not available. " +
             "Add CGLIB to the class path or specify proxy interfaces.");
       }
       // 這裡使用Cglib來生成Proxy,如果target不是接口的實現的話,返回 cglib類型的AopProxy
       return CglibProxyFactory.createCglibProxy(advisedSupport);
     }
     else {
       // 這裡使用JDK來生成Proxy,返回JDK類型的AopProxy
       return new JdkDynamicAopProxy(advisedSupport);
     }
   }

於是我們就可以看到其中的代理對象可以由JDK或者Cglib來生成,我們看到 JdkDynamicAopProxy類和Cglib2AopProxy都實現的是AopProxy的接口,在 JdkDynamicAopProxy實現中我們可以看到Proxy是怎樣生成的:

Java代碼

public Object getProxy(ClassLoader classLoader) {
     if (logger.isDebugEnabled()) {
       Class targetClass = this.advised.getTargetSource ().getTargetClass();
       logger.debug("Creating JDK dynamic proxy" +
           (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
     }
     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
     //這裡我們調用JDK Proxy來生成需要的Proxy實例
     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
   }

這樣用Proxy包裝target之後,通過ProxyFactoryBean得到對其方法的調用就被Proxy 攔截了, ProxyFactoryBean的getObject()方法得到的實際上是一個Proxy了,我們的 target對象已經被封裝了。對 ProxyFactoryBean這個工廠bean而言,其生產出來的對象 是封裝了目標對象的代理對象。

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