The important thing in life is to have a great aim , and the determination

          常用鏈接

          統(tǒng)計

          IT技術(shù)鏈接

          保險相關(guān)

          友情鏈接

          基金知識

          生活相關(guān)

          最新評論

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

          下面我們來看看Spring的AOP的一些相關(guān)代碼是怎么得到Proxy的,讓我們我們先看看AOP和Spring AOP的一些基本概念:
          Advice:
              通知,制定在連接點做什么,在Sping中,他主要描述Spring圍繞方法調(diào)用注入的額外的行為,Spring提供的通知類型有:
              before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,這些都是Spring AOP定義的接口類,具體的動作實現(xiàn)需要用戶程序來完成。
          Pointcut:
              切點,其決定一個advice應(yīng)該應(yīng)用于哪個連接點,也就是需要插入額外處理的地方的集合,例如,被某個advice作為目標的一組方法。Spring pointcut通常意味著標示方法,可以選擇一組方法調(diào)用作為pointcut,Spring提供了具體的切點來給用戶使用,比如正則表達式切點 JdkRegexpMethodPointcut通過正則表達式對方法名進行匹配,其通過使用 AbstractJdkRegexpMethodPointcut中的對MethodMatcher接口的實現(xiàn)來完成pointcut功能:
          Java代碼 復(fù)制代碼 收藏代碼
          1. public final boolean matches(Method method, Class targetClass) {   
          2.     //這里通過放射得到方法的全名   
          3.     String patt = method.getDeclaringClass().getName() + "." + method.getName();   
          4.     for (int i = 0; i < this.patterns.length; i++) {   
          5.         // 這里是判斷是否和方法名是否匹配的代碼   
          6.         boolean matched = matches(patt, i);   
          7.         if (matched) {   
          8.             for (int j = 0; j < this.excludedPatterns.length; j++) {   
          9.                 boolean excluded = matchesExclusion(patt, j);   
          10.                 if(excluded) {   
          11.                     return false;   
          12.                 }   
          13.             }   
          14.             return true;   
          15.         }   
          16.     }   
          17.     return false;   
          18. }  

          在JDKRegexpMethodPointcut中通過JDK中的正則表達式匹配來完成pointcut的最終確定:
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected boolean matches(String pattern, int patternIndex) {   
          2.     Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);   
          3.     return matcher.matches();   
          4. }  

          Advisor:
          當我們完成額外的動作設(shè)計(advice)和額外動作插入點的設(shè)計(pointcut)以后,我們需要一個對象把他們結(jié)合起來,這就是通知器 - advisor,定義應(yīng)該在哪里應(yīng)用哪個通知。Advisor的實現(xiàn)有:DefaultPointcutAdvisor他有兩個屬性advice和 pointcut來讓我們配置advice和pointcut。
          接著我們就可以通過ProxyFactoryBean來配置我們的代理對象和方面行為,在ProxyFactoryBean中有interceptorNames來配置已經(jīng)定義好的通知器-advisor,雖然這里的名字叫做interceptNames,但實際上是供我們配置advisor的地方,具體的代理實現(xiàn)通過JDK 的Proxy或者CGLIB來完成。因為ProxyFactoryBean是一個FactoryBean,在ProxyFactoryBean中我們通過getObject()可以直接得到代理對象:
          Java代碼 復(fù)制代碼 收藏代碼
          1. public Object getObject() throws BeansException {   
          2.     //這里初始化通知器鏈   
          3.     initializeAdvisorChain();   
          4.     if (isSingleton()) {   
          5.     //根據(jù)定義需要生成單件的Proxy   
          6.         return getSingletonInstance();   
          7.     }   
          8.     else {   
          9.     .......   
          10.         //這里根據(jù)定義需要生成Prototype類型的Proxy   
          11.         return newPrototypeInstance();   
          12.     }   
          13. }  

          我們看看怎樣生成單件的代理對象:
          Java代碼 復(fù)制代碼 收藏代碼
          1. private synchronized Object getSingletonInstance() {   
          2.     if (this.singletonInstance == null) {   
          3.         this.targetSource = freshTargetSource();   
          4.         if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {   
          5.             // 這里設(shè)置代理對象的接口   
          6.             setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));   
          7.         }   
          8.         // Eagerly initialize the shared singleton instance.   
          9.         super.setFrozen(this.freezeProxy);   
          10.         // 注意這里的方法會使用ProxyFactory來生成我們需要的Proxy   
          11.         this.singletonInstance = getProxy(createAopProxy());   
          12.         // We must listen to superclass advice change events to recache the singleton   
          13.         // instance if necessary.   
          14.         addListener(this);   
          15.     }   
          16.     return this.singletonInstance;   
          17. }   
          18.   
          19. //使用createAopProxy放回的AopProxy來得到代理對象。   
          20. protected Object getProxy(AopProxy aopProxy) {   
          21.     return aopProxy.getProxy(this.beanClassLoader);   
          22. }  

          ProxyFactoryBean的父類是AdvisedSupport,Spring使用AopProxy接口把AOP代理的實現(xiàn)與框架的其他部分分離開來;在AdvisedSupport中通過這樣的方式來得到AopProxy,當然這里需要得到AopProxyFactory的幫助 - 下面我們看到Spring為我們提供的實現(xiàn),來幫助我們方便的從JDK或者cglib中得到我們想要的代理對象:
          Java代碼 復(fù)制代碼 收藏代碼
          1. protected synchronized AopProxy createAopProxy() {   
          2.     if (!this.isActive) {   
          3.         activate();   
          4.     }   
          5.     return getAopProxyFactory().createAopProxy(this);   
          6. }  

          而在ProxyConfig中對使用的AopProxyFactory做了定義:
          Java代碼 復(fù)制代碼 收藏代碼
          1. //這個DefaultAopProxyFactory是Spring用來生成AopProxy的地方,   
          2. //當然了它包含JDK和Cglib兩種實現(xiàn)方式。   
          3. private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();  

          其中在DefaultAopProxyFactory中是這樣生成AopProxy的:
          Java代碼 復(fù)制代碼 收藏代碼
          1. public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {   
          2.     //首先考慮使用cglib來實現(xiàn)代理對象,當然如果同時目標對象不是接口的實現(xiàn)類的話   
          3.     if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||   
          4.         advisedSupport.getProxiedInterfaces().length == 0) {   
          5.         //這里判斷如果不存在cglib庫,直接拋出異常。   
          6.         if (!cglibAvailable) {   
          7.             throw new AopConfigException(   
          8.                     "Cannot proxy target class because CGLIB2 is not available. " +   
          9.                     "Add CGLIB to the class path or specify proxy interfaces.");   
          10.         }   
          11.         // 這里使用Cglib來生成Proxy,如果target不是接口的實現(xiàn)的話,返回cglib類型的AopProxy   
          12.         return CglibProxyFactory.createCglibProxy(advisedSupport);   
          13.     }   
          14.     else {   
          15.         // 這里使用JDK來生成Proxy,返回JDK類型的AopProxy   
          16.         return new JdkDynamicAopProxy(advisedSupport);   
          17.     }   
          18. }  

          于是我們就可以看到其中的代理對象可以由JDK或者Cglib來生成,我們看到JdkDynamicAopProxy類和Cglib2AopProxy都實現(xiàn)的是AopProxy的接口,在JdkDynamicAopProxy實現(xiàn)中我們可以看到Proxy是怎樣生成的:
          Java代碼 復(fù)制代碼 收藏代碼
          1. public Object getProxy(ClassLoader classLoader) {   
          2.     if (logger.isDebugEnabled()) {   
          3.         Class targetClass = this.advised.getTargetSource().getTargetClass();   
          4.         logger.debug("Creating JDK dynamic proxy" +   
          5.                 (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));   
          6.     }   
          7.     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);   
          8.     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);   
          9.     //這里我們調(diào)用JDK Proxy來生成需要的Proxy實例   
          10.     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);   
          11. }  

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

          posted on 2011-10-26 23:39 鴻雁 閱讀(244) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 盐源县| 九龙县| 潞西市| 章丘市| 阳信县| 静海县| 日喀则市| 平顶山市| 禄丰县| 南靖县| 英山县| 开鲁县| 吉林省| 苏尼特左旗| 星子县| 营口市| 天台县| 砀山县| 河东区| 沙雅县| 澄迈县| 潢川县| 江西省| 诸暨市| 阿克| 色达县| 太仆寺旗| 满城县| 安乡县| 长宁区| 麻江县| 柘荣县| 巴东县| 靖江市| 谷城县| 毕节市| 贡觉县| 汉中市| 清涧县| 福海县| 三河市|