我的漫漫程序之旅

          專注于JavaWeb開(kāi)發(fā)
          隨筆 - 39, 文章 - 310, 評(píng)論 - 411, 引用 - 0

          導(dǎo)航

          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(39)

          隨筆檔案(43)

          文章分類(304)

          文章檔案(257)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          Spring AOP初探

           AOP正在成為軟件開(kāi)發(fā)的下一個(gè)圣杯。使用AOP,你可以將處理aspect的代碼注入主程序,通常主程序的主要目的并不在于處理這些aspect。AOP可以防止代碼混亂。
          為了理解AOP如何做到這點(diǎn),考慮一下記日志的工作。日志本身不太可能是你開(kāi)發(fā)的主程序的主要任務(wù)。如果能將“不可見(jiàn)的”、通用的日志代碼注入主程序中,那該多好啊。AOP可以幫助你做到。
          Spring framework是很有前途的AOP技術(shù)。作為一種非侵略性的,輕型的AOP framework,你無(wú)需使用預(yù)編譯器或其他的元標(biāo)簽,便可以在Java程序中使用它。這意味著開(kāi)發(fā)團(tuán)隊(duì)里只需一人要對(duì)付AOP framework,其他人還是象往常一樣編程。
          AOP是很多直覺(jué)難以理解的術(shù)語(yǔ)的根源。幸運(yùn)的是,你只要理解三個(gè)概念,就可以編寫AOP模塊。這三個(gè)概念是:advice,pointcut和 advisor。advice是你想向別的程序內(nèi)部不同的地方注入的代碼。pointcut定義了需要注入advice的位置,通常是某個(gè)特定的類的一個(gè) public方法。advisor是pointcut和advice的裝配器,是將advice注入主程序中預(yù)定義位置的代碼。

          既然我們知道了需要使用advisor向主要代碼中注入“不可見(jiàn)的”advice,讓我們實(shí)現(xiàn)一個(gè)Spring AOP的例子。在這個(gè)例子中,我們將實(shí)現(xiàn)一個(gè)before advice,這意味著advice的代碼在被調(diào)用的public方法開(kāi)始前被執(zhí)行。以下是這個(gè)before advice的實(shí)現(xiàn)代碼:

          package com.company.springaop.test; 

          import java.lang.reflect.Method; 
          import org.springframework.aop.MethodBeforeAdvice; 

          public class TestBeforeAdvice implements MethodBeforeAdvice 

            
          public void before(Method m, Object[] args, Object target) 
            
          throws Throwable 
              System.out.println(
          "Hello world! (by " 
                  
          + this.getClass().getName() 
                  
          + ")"); 
            }
           
          }
           


          接口MethodBeforeAdvice只有一個(gè)方法before需要實(shí)現(xiàn),它定義了advice的實(shí)現(xiàn)。before方法共用三個(gè)參數(shù),它們提供了相當(dāng)豐富的信息。參數(shù)Method m是advice開(kāi)始后執(zhí)行的方法。方法名稱可以用作判斷是否執(zhí)行代碼的條件。Object[] args是傳給被調(diào)用的public方法的參數(shù)數(shù)組。當(dāng)需要記日志時(shí),參數(shù)args和被執(zhí)行方法的名稱,都是非常有用的信息。你也可以改變傳給m的參數(shù),但要小心使用這個(gè)功能;編寫最初主程序的程序員并不知道主程序可能會(huì)和傳入?yún)?shù)的發(fā)生沖突。Object target是執(zhí)行方法m對(duì)象的引用。

          在下面的BeanImpl類中,每個(gè)public方法調(diào)用前,都會(huì)執(zhí)行advice:

          package com.company.springaop.test; 

          public class BeanImpl implements Bean 

            
          public void theMethod() 
              System.out.println(
          this.getClass().getName() 
                  
          + "." + new Exception().getStackTrace()[0].getMethodName() 
                  
          + "()" 
                  
          + " says HELLO!"); 
            }
           
          }


          類BeanImpl實(shí)現(xiàn)了下面的接口Bean:

          package com.company.springaop.test; 

          public interface Bean 
            
          public void theMethod(); 
          }



          雖然不是必須使用接口,但面向接口而不是面向?qū)崿F(xiàn)編程是良好的編程實(shí)踐,Spring也鼓勵(lì)這樣做。

          pointcut和advice通過(guò)配置文件來(lái)實(shí)現(xiàn),因此,接下來(lái)你只需編寫主方法的Java代碼:
          package com.company.springaop.test; 

          import org.springframework.context.ApplicationContext; 
          import org.springframework.context.support.FileSystemXmlApplicationContext; 

          public class Main 

            
          public static void main(String[] args) 
              
          //Read the configuration file 
              ApplicationContext ctx 
                  
          = new FileSystemXmlApplicationContext("springconfig.xml"); 

              
          //Instantiate an object 
              Bean x = (Bean) ctx.getBean("bean"); 

              
          //Execute the public method of the bean (the test) 
              x.theMethod(); 
            }
           
          }



          我們從讀入和處理配置文件開(kāi)始,接下來(lái)馬上要?jiǎng)?chuàng)建它。這個(gè)配置文件將作為粘合程序不同部分的“膠水”。讀入和處理配置文件后,我們會(huì)得到一個(gè)創(chuàng)建工廠ctx。任何一個(gè)Spring管理的對(duì)象都必須通過(guò)這個(gè)工廠來(lái)創(chuàng)建。對(duì)象通過(guò)工廠創(chuàng)建后便可正常使用。

          僅僅用配置文件便可把程序的每一部分組裝起來(lái)。
          <?xml version="1.0" encoding="UTF-8"?> 
          <!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> 

          <beans> 
            
          <!--CONFIG--> 
            
          <bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
              
          <property name="proxyInterfaces"> 
                
          <value>com.company.springaop.test.Bean</value> 
              
          </property> 
              
          <property name="target"> 
                
          <ref local="beanTarget"/> 
              
          </property> 
              
          <property name="interceptorNames"> 
                
          <list> 
                  
          <value>theAdvisor</value> 
                
          </list> 
              
          </property> 
            
          </bean> 

            
          <!--CLASS--> 
            
          <bean id="beanTarget" class="com.company.springaop.test.BeanImpl"/> 

            
          <!--ADVISOR--> 
            
          <!--Note: An advisor assembles pointcut and advice--> 
            
          <bean id="theAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
              
          <property name="advice"> 
                
          <ref local="theBeforeAdvice"/> 
              
          </property> 
              
          <property name="pattern"> 
                
          <value>com\.company\.springaop\.test\.Bean\.theMethod</value> 
              
          </property> 
            
          </bean> 

            
          <!--ADVICE--> 
            
          <bean id="theBeforeAdvice" class="com.company.springaop.test.TestBeforeAdvice"/> 
          </beans> 


          四個(gè)bean定義的次序并不重要。我們現(xiàn)在有了一個(gè)advice,一個(gè)包含了正則表達(dá)式pointcut的advisor,一個(gè)主程序類和一個(gè)配置好的接口,通過(guò)工廠ctx,這個(gè)接口返回自己本身實(shí)現(xiàn)的一個(gè)引用。

          BeanImpl和TestBeforeAdvice都是直接配置。我們用一個(gè)唯一的ID創(chuàng)建一個(gè)bean元素,并指定了一個(gè)實(shí)現(xiàn)類。這就是全部的工作。

          advisor通過(guò)Spring framework提供的一個(gè)RegexMethodPointcutAdvisor類來(lái)實(shí)現(xiàn)。我們用advisor的一個(gè)屬性來(lái)指定它所需的 advice-bean。第二個(gè)屬性則用正則表達(dá)式定義了pointcut,確保良好的性能和易讀性。

          最后配置的是bean,它可以通過(guò)一個(gè)工廠來(lái)創(chuàng)建。bean的定義看起來(lái)比實(shí)際上要復(fù)雜。bean是ProxyFactoryBean的一個(gè)實(shí)現(xiàn),它是Spring framework的一部分。這個(gè)bean的行為通過(guò)一下的三個(gè)屬性來(lái)定義:


          • 屬性proxyInterface定義了接口類。
          • 屬性target指向本地配置的一個(gè)bean,這個(gè)bean返回一個(gè)接口的實(shí)現(xiàn)。
          • 屬性interceptorNames是唯一允許定義一個(gè)值列表的屬性。這個(gè)列表包含所有需要在beanTarget上執(zhí)行的advisor。注意,advisor列表的次序是非常重要的。


          Spring工具

          雖然你可以手工修改Ant構(gòu)建腳本,但使用SpringUI(譯注:SpringUI現(xiàn)在是Spring framework的一部分,并改名為spring-ide),使用Spring AOP變得很簡(jiǎn)單,只要點(diǎn)點(diǎn)鼠標(biāo)即可。你可以把SpringUI安裝成Eclipse的一個(gè)plug-in。然后,你只需在你的project上右擊鼠標(biāo),并選擇“add Spring Project Nature”。在project屬性中,你可以在“Spring Project”下添加Spring配置文件。在編譯前把下面的類庫(kù)加入project:aopalliance.jar,commons- logging.jar,jakarta-oro-2.0.7.jar和spring.jar。運(yùn)行程序時(shí)你會(huì)看到下面的信息:

           (logging information) 
          Hello world! (by com.company.springaop.test.TestBeforeAdvice) 
          com.company.springaop.test.BeanImpl.theMethod() says HELLO! 



          優(yōu)點(diǎn)和缺點(diǎn)

          Spring比起其他的framework更有優(yōu)勢(shì),因?yàn)槌薃OP以外,它提供了更多別的功能。作為一個(gè)輕型framework,它在J2EE 不同的部分都可以發(fā)揮作用。因此,即使不想使用Spring AOP,你可能還是想使用Spring。另一個(gè)優(yōu)點(diǎn)是,Spring并不要求開(kāi)發(fā)團(tuán)隊(duì)所有的人員都會(huì)用它。學(xué)習(xí)Spring應(yīng)該從Spring reference的第一頁(yè)開(kāi)始。讀了本文后,你應(yīng)該可以更好地理解Spring reference了。Spring唯一的缺點(diǎn)是缺乏更多的文檔,但它的mailing list是個(gè)很好的補(bǔ)充,而且會(huì)不斷地出現(xiàn)更多的文檔。
           


          posted on 2007-12-31 21:48 々上善若水々 閱讀(897) 評(píng)論(0)  編輯  收藏 所屬分類: Spring

          主站蜘蛛池模板: 商都县| 蓬溪县| 兴化市| 绵竹市| 社会| 盘山县| 镇江市| 色达县| 六安市| 岫岩| 寻乌县| 通海县| 凉山| 郸城县| 合阳县| 剑河县| 北宁市| 镇巴县| 镇雄县| 张掖市| 海淀区| 佛坪县| 蓝田县| 金堂县| 万盛区| 龙岩市| 青阳县| 甘泉县| 昭觉县| 赣榆县| 神木县| 郯城县| 通化县| 浦东新区| 铁力市| 金塔县| 方山县| 瑞金市| 南丹县| 屏山县| 孟连|