stone2083

          活用Srping AOP

          總有那么一些代碼,在測試環(huán)境下,是不能輕易被調(diào)用的。
          比如:
          1)發(fā)送系統(tǒng)任務(wù)郵件到客戶郵箱,可能一不小心,就把測試郵件發(fā)送給了真實(shí)客戶的郵箱里;
          2)調(diào)用跨公司的系統(tǒng)接口,而對方系統(tǒng)沒有測試環(huán)境,每調(diào)用一次接口,就會(huì)在對方系統(tǒng)產(chǎn)生垃圾數(shù)據(jù);
          3)調(diào)用的代碼可能需要大量的cpu運(yùn)算,占用大量的內(nèi)存空間,消耗大量的資源;
          等等。。。

          為了解決這樣的需求,
          1)在代碼中,到處充斥著這樣的代碼:
          1 if(在測試環(huán)境下) {
          2     打印日志;
          3 else {
          4     調(diào)用真實(shí)的業(yè)務(wù)邏輯;
          5 }
          于是乎,需要到處維護(hù)這樣的代碼,一旦增加此類需求,就需要編寫同樣的代碼

          2)部分懶惰的程序員,連這樣的if...else...也不愿意寫,僅僅在注釋中說明下在測試環(huán)境中調(diào)用方法的危害性。
          于是,在測試階段,一旦和測試部門溝通不足,導(dǎo)致代碼還是經(jīng)常被調(diào)用到,如果是在作壓力,性能測試,那么危害性可想而已。
          曾發(fā)生過,壓力測試某個(gè)功能,結(jié)果把大量的測試郵件,發(fā)送給了客戶,影響很差。


          那么,如何解決這樣的需求場景呢?
          沒錯(cuò),采用proxy模式,可以搞定。考慮到現(xiàn)在很多企業(yè)都使用Spring作為IOC容器,本文就簡單介紹,如何采用spring aop來解決問題。

          以發(fā)送郵件的需求作為虛擬場景。
          現(xiàn)在有個(gè)Service,專門負(fù)責(zé)郵件的發(fā)送。
          1. MyService.java
          1 public class MyService {
          2     public void sendMailSafely() {
          3     System.out.println("send mail successfully.");
          4     }
          5 }

          如果這個(gè)sendMailSafely被客戶端調(diào)用,那么毫無疑問,郵件不管任何環(huán)境下,都會(huì)被成功發(fā)送。
          需要有個(gè)方法攔截器,對這個(gè)方法做攔截。
          2. MyInterceptor.java
           1 public class MyInterceptor implements MethodInterceptor {
           2 
           3     private boolean isProduction = false;
           4 
           5     @Override
           6     public Object invoke(MethodInvocation invocation) throws Throwable {
           7     if (!isProduction) {
           8         System.out.println("is production environment.do nothing");
           9         return null;
          10     }
          11     return invocation.proceed();
          12     }
          13 
          14     public void setProduction(boolean isProduction) {
          15     this.isProduction = isProduction;
          16     }
          17 
          18 }
          這個(gè)攔截器,根據(jù)配置文件的參數(shù)isProduction判斷是否在正式環(huán)境,如果是在測試環(huán)境,對方法做攔截,僅僅打印log,不真實(shí)調(diào)用業(yè)務(wù)邏輯。

          如何讓sendMailSafely()方法被此攔截器做攔截,所以通過spring配置文件,配置一個(gè)advisor,通知對以Safely結(jié)尾的方法做攔截
          3.  application.xml
           1 <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
           2     <property name="advice">
           3       <ref local="myInterceptor" />
           4     </property>
           5     <property name="patterns">
           6       <list>
           7         <value>.*Safely</value>
           8       </list>
           9     </property>
          10   </bean>

          附上application.xml的全部內(nèi)容
           1 <beans default-autowire="byName">
           2 
           3   <!-- service實(shí)例 -->
           4   <bean id="myService" class="cn.zeroall.javalab.aop.MyService" scope="singleton" />
           5 
           6   <!-- 方法攔截器 -->
           7   <bean id="myInterceptor" class="cn.zeroall.javalab.aop.MyInterceptor" scope="singleton">
           8     <property name="production" value="false" />
           9   </bean>
          10 
          11   <!-- 通知者 -->
          12   <bean id="safetyAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" scope="singleton">
          13     <property name="advice">
          14       <ref local="myInterceptor" />
          15     </property>
          16     <property name="patterns">
          17       <list>
          18         <value>.*Safely</value>
          19       </list>
          20     </property>
          21   </bean>
          22 
          23   <!-- myService代理類 -->
          24   <bean id="safetyService" class="org.springframework.aop.framework.ProxyFactoryBean" scope="singleton">
          25     <property name="interceptorNames">
          26       <list>
          27         <value>safetyAdvisor</value>
          28       </list>
          29     </property>
          30     <property name="targetName" value="myService" />
          31   </bean>
          32 
          33 </beans>


          寫一個(gè)Client類來做演示。
          4. Client.java
           1 public class Client {
           2 
           3     private ApplicationContext ctx = new ClassPathXmlApplicationContext(
           4         "cn/zeroall/javalab/aop/application.xml");;
           5 
           6     public static void main(String[] args) {
           7         Client c = new Client();
           8         c.sendMail();
           9         c.sendMailSafety();
          10     }
          11 
          12     public void sendMail() {
          13         MyService myService = (MyService) ctx.getBean("myService");
          14         myService.sendMailSafely();
          15     }
          16 
          17     public void sendMailSafety() {
          18         MyService myService = (MyService) ctx.getBean("safetyService");
          19         myService.sendMailSafely();
          20     }
          21 
          22 }
          大家可以看看最終輸出的結(jié)果內(nèi)容。

          一直來,我都不會(huì)濫用AOP,尤其反感使用AOP來寫業(yè)務(wù)邏輯內(nèi)容,但是對于這類非業(yè)務(wù)邏輯需求,采用spring aop技術(shù)那是剛剛好啊。

          最后,附上全部代碼文件(使用maven構(gòu)建)。
          演示代碼

          posted on 2008-06-01 15:21 stone2083 閱讀(508) 評(píng)論(0)  編輯  收藏 所屬分類: java

          My Links

          Blog Stats

          常用鏈接

          留言簿(9)

          隨筆分類(94)

          隨筆檔案(93)

          tech

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 杨浦区| 济南市| 夏津县| 巴彦淖尔市| 正镶白旗| 台南市| 三门县| 公安县| 金堂县| 湾仔区| 内丘县| 湘乡市| 招远市| 山东省| 兴文县| 汉中市| 本溪| 青铜峡市| 大埔区| 威远县| 上杭县| 阿克| 北流市| 北安市| 尼玛县| 炎陵县| 通辽市| 海丰县| 通州区| 惠安县| 荣昌县| 塘沽区| 清流县| 临澧县| 甘孜县| 景洪市| 闻喜县| 和林格尔县| 安阳市| 夏津县| 胶州市|