和爪哇一起走過的日子

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            12 隨筆 :: 0 文章 :: 6 評論 :: 0 Trackbacks
          AOP正在成為軟件開發的下一個圣杯。使用AOP,你可以將處理aspect的代碼注入主程序,通常主程序的主要目的并不在于處理這些aspect。AOP可以防止代碼混亂。
          為了理解AOP如何做到這點,考慮一下記日志的工作。日志本身不太可能是你開發的主程序的主要任務。如果能將“不可見的”、通用的日志代碼注入主程序中,那該多好啊。AOP可以幫助你做到。
          Spring framework是很有前途的AOP技術。作為一種非侵略性的,輕型的AOP framework,你無需使用預編譯器或其他的元標簽,便可以在Java程序中使用它。這意味著開發團隊里只需一人要對付AOP framework,其他人還是象往常一樣編程。
          AOP是很多直覺難以理解的術語的根源。幸運的是,你只要理解三個概念,就可以編寫AOP模塊。這三個概念是:advice,pointcut和advisor。advice是你想向別的程序內部不同的地方注入的代碼。pointcut定義了需要注入advice的位置,通常是某個特定的類的一個public方法。advisor是pointcut和advice的裝配器,是將advice注入主程序中預定義位置的代碼。

          既然我們知道了需要使用advisor向主要代碼中注入“不可見的”advice,讓我們實現一個Spring AOP的例子。在這個例子中,我們將實現一個before advice,這意味著advice的代碼在被調用的public方法開始前被執行。以下是這個before advice的實現代碼:

          代碼:
          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只有一個方法before需要實現,它定義了advice的實現。before方法共用三個參數,它們提供了相當豐富的信息。參數Method m是advice開始后執行的方法。方法名稱可以用作判斷是否執行代碼的條件。Object[] args是傳給被調用的public方法的參數數組。當需要記日志時,參數args和被執行方法的名稱,都是非常有用的信息。你也可以改變傳給m的參數,但要小心使用這個功能;編寫最初主程序的程序員并不知道主程序可能會和傳入參數的發生沖突。Object target是執行方法m對象的引用。

          在下面的BeanImpl類中,每個public方法調用前,都會執行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實現了下面的接口Bean:

          代碼:
          package com.company.springaop.test;

          public interface Bean {
          public void theMethod();
          }

          雖然不是必須使用接口,但面向接口而不是面向實現編程是良好的編程實踐,Spring也鼓勵這樣做。

          pointcut和advice通過配置文件來實現,因此,接下來你只需編寫主方法的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();
          }
          }

          我們從讀入和處理配置文件開始,接下來馬上要創建它。這個配置文件將作為粘合程序不同部分的“膠水”。讀入和處理配置文件后,我們會得到一個創建工廠ctx。任何一個Spring管理的對象都必須通過這個工廠來創建。對象通過工廠創建后便可正常使用。

          僅僅用配置文件便可把程序的每一部分組裝起來。
          代碼:

          <?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>


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

          BeanImpl和TestBeforeAdvice都是直接配置。我們用一個唯一的ID創建一個bean元素,并指定了一個實現類。這就是全部的工作。

          advisor通過Spring framework提供的一個RegexMethodPointcutAdvisor類來實現。我們用advisor的一個屬性來指定它所需的advice-bean。第二個屬性則用正則表達式定義了pointcut,確保良好的性能和易讀性。

          最后配置的是bean,它可以通過一個工廠來創建。bean的定義看起來比實際上要復雜。bean是ProxyFactoryBean的一個實現,它是Spring framework的一部分。這個bean的行為通過一下的三個屬性來定義:


          屬性proxyInterface定義了接口類。

          屬性target指向本地配置的一個bean,這個bean返回一個接口的實現。

          屬性interceptorNames是唯一允許定義一個值列表的屬性。這個列表包含所有需要在beanTarget上執行的advisor。注意,advisor列表的次序是非常重要的。

          Spring工具

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

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


          優點和缺點

          Spring比起其他的framework更有優勢,因為除了AOP以外,它提供了更多別的功能。作為一個輕型framework,它在J2EE不同的部分都可以發揮作用。因此,即使不想使用Spring AOP,你可能還是想使用Spring。另一個優點是,Spring并不要求開發團隊所有的人員都會用它。學習Spring應該從Spring reference的第一頁開始。讀了本文后,你應該可以更好地理解Spring reference了。Spring唯一的缺點是缺乏更多的文檔,但它的mailing list是個很好的補充,而且會不斷地出現更多的文檔

          posted on 2005-10-14 09:05 撲撲 閱讀(2625) 評論(4)  編輯  收藏 所屬分類: Spring

          評論

          # re: Spring Aop簡單實例入門 2005-10-14 09:12 撲撲
          昨晚重新翻出這篇看了看,打算把它用在這次項目的權限控制上.通過對service層方法做攔截,在攔截方法中對用戶的權限做判斷,最后確定是否繼續后續的操作.關天權限模型的實現還要參考ACL和RBAC.  回復  更多評論
            

          # re: Spring Aop簡單實例入門 2006-07-26 18:14 智者無疆
          我用你的代碼做測試了,但只出現了com.company.springaop.test.BeanImpl.theMethod() says HELLO! ,而沒有出現Hello world! (by com.company.springaop.test.TestBeforeAdvice) ,請教這是為什么,有時間請指教指教!!我的QQ:280199080  回復  更多評論
            

          # re: Spring Aop簡單實例入門 2006-12-05 17:26 剛調試過這個程序,調試不過
          出現異常
          org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bean' defined in file [D:\Eclipse\eclipse\workspace\testspring\src\springconf.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.FatalBeanException: Could not instantiate class [org.springframework.aop.framework.ProxyFactoryBean]; constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.isPresent(Ljava/lang/String;)Z
          org.springframework.beans.FatalBeanException: Could not instantiate class [org.springframework.aop.framework.ProxyFactoryBean]; constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.isPresent(Ljava/lang/String;)Z
          java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.isPresent(Ljava/lang/String;)Z
          at org.springframework.aop.framework.DefaultAopProxyFactory.<clinit>(DefaultAopProxyFactory.java:57)
          at org.springframework.aop.framework.ProxyConfig.<init>(ProxyConfig.java:72)
          at org.springframework.aop.framework.AdvisedSupport.<init>(AdvisedSupport.java:103)
          at org.springframework.aop.framework.ProxyFactoryBean.<init>(ProxyFactoryBean.java:88)
          at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
          at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
          at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
          at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
          at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172)
          at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
          at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:49)
          at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:453)
          at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:333)
          at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:226)
          at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:147)
          at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:269)
          at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:320)
          at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:89)
          at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:74)
          at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:65)
          幫忙解決一下,3kq!
            回復  更多評論
            

          # re: Spring Aop簡單實例入門 2012-07-16 16:28 yeahwell
          @撲撲
          兄弟,我最近剛好在和你做同樣的事。使用AOP攔截Service層的方法,來達到RBAC級別的權限控制,你實現了么,我遇到了一個問題、  回復  更多評論
            

          主站蜘蛛池模板: 扎鲁特旗| 莲花县| 黄浦区| 虎林市| 常山县| 治多县| 青浦区| 明星| 霍邱县| 德保县| 四子王旗| 永德县| 砀山县| 田东县| 布尔津县| 若羌县| 彩票| 中卫市| 镇巴县| 临高县| 洞口县| 泰和县| 三河市| 横山县| 赣榆县| 襄汾县| 桂阳县| 海门市| 仁寿县| 佳木斯市| 湟源县| 建平县| 万载县| 温宿县| 手机| 宣武区| 定远县| 丹江口市| 丹凤县| 宽城| 甘德县|