<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    常言笑的家

    Spring, Hibernate, Struts, Ajax, RoR

    Spring Aop Step-By-Step 學(xué)習(xí)筆記(下)

    五. Spring-Aop 引入的介紹
     
        下面我們介紹一種通知“引入”,關(guān)于引入,如同它的名字一樣,給對象添加方法和屬性。呵呵,好厲害吧。它是通過CBLIB來動態(tài)生成類的,所以自己用的時候別忘了加載這個包。
        
         代碼:
         購物時候放東西的包包;
    public interface CustomerBag {
         void addBag(Object obj);
     
         void clean();
     
         int getCount();
    }
     
    我們要給別的對象類添加的Mixin,嘿嘿。
    public class CustomerMixin extends DelegatingIntroductionInterceptor implements CustomerBag {
     
         private static final long serialVersionUID = 5296015143432822715L;
        
         private ArrayList bag = new ArrayList();
     
         public void addBag(Object obj) {
              bag.add(obj);
         }
     
         public void clean() {
              bag = new ArrayList();
         }
     
         public ArrayList getBag() {
              return bag;
         }
     
         public int getCount() {
              return bag.size();
         }
     
    }
     
         我們的xml文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
    <beans>
        
         <bean id="customer" class="demo.Customer" singleton="false" />
     
         <bean id="customerMixin" class="demo.CustomerMixin" singleton="false" />
     
     
         <bean id="customerMixinAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
              singleton="false">
              <constructor-arg>
                   <ref bean="customerMixin" />
              </constructor-arg>
         </bean>
     
         <bean id="customerBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="proxyTargetClass" value="true" />
              <property name="singleton" value="false" />
              <property name="interceptorNames">
                   <list>
                        <value>customerMixinAdvisor</value>
                   </list>
              </property>
              <property name="target">
                   <ref bean="customer" />
              </property>
         </bean>
     
    </beans>
     
    可以看到singleton="false"處處可見,因為我們要每個新的對象都有自己引入的狀態(tài),不可能只有一個對象來維持,那個我們肯定是不希望的。
    修改我們的RunDemo類,添加一個方法:
         /**
          * 創(chuàng)建引用通知;
          */
         public static void customer() {
     
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/customer.xml");
     
              // 這個類是有CGLIB動態(tài)生成的;
              Customer bag = (Customer) context.getBean("customerBean");
              CustomerBag bag2 = (CustomerBag) bag;
              bag2.addBag(new Object());
     
              System.out.println(bag.getName());
              System.out.println(bag2.getCount());
         }
     
              在main中調(diào)用這個方法,運行,結(jié)果如下:
                  
                   悠~游!
    1
     
              在這里我要說明一下,關(guān)于引入這個通知的使用我僅僅是看了一眼,具體的例子可能有不恰當(dāng)之處還請高手們指點。
     
    六. Spring-Aop 之 BeanNameAutoProxyCreator
     
    BeanNameAutoProxyCreator 看其名,大概知道其意。根據(jù)bean的名字自動匹配攔截代理,讓我們看看它能帶來什么?
    代碼:
    public class PerformanceThresholdInterceptor implements MethodInterceptor {
     
         private final long thresholdInMillis;
     
         PerformanceThresholdInterceptor(long time) {
              thresholdInMillis = time;
     
         }
     
         public Object invoke(MethodInvocation invocation) throws Throwable {
             
              System.out.println(" 開始測試時間.");
              long t = System.currentTimeMillis();
              Object o = invocation.proceed();
              t = System.currentTimeMillis() - t;
              if (t > thresholdInMillis) {
                   System.out.println(" 警告:調(diào)用的方法所耗費的時間超過預(yù)警時間(" + thresholdInMillis + " 微秒)");
              }
              System.out.println(" 測試時間結(jié)束.");
              return o;
         }
    }
    這個又是自定義的,呵呵。我們繼承MethodInterceptor這換類,實現(xiàn)我們自己的方法過濾器。具體要實現(xiàn)的功能就是檢驗我們要調(diào)用的方法,和OnePerCustomerInterceptor這個類一樣。
    接下來是我們的xml文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
    <beans>
         <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
        
         <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
              <constructor-arg>
                   <value>5000</value>
              </constructor-arg>
         </bean>
     
         <bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
              <property name="beanNames">
                   <list>
                        <value>*Target</value>
                   </list>
              </property>
              <property name="interceptorNames">
                   <value>performanceThresholdInterceptor</value>
              </property>
         </bean>
     
    </beans>
     
    在main方法中加入我們的方法:
       /**
        * 創(chuàng)建beanNameAutoProxyCreator動態(tài)代理;
        */
       public static void beanNameProxy() {
     
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/beanNameProxy.xml");
     
            KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
            try {
                 akem.buyCheese(new Customer());
            } catch (KwikEMartException e) {
                 e.printStackTrace();
            }
       }
     
         運行我們的例子,結(jié)果如下:
        
    開始測試時間.
    -- 我想買:奶酪!
    測試時間結(jié)束.
        
         看到了么?Spring aop自動尋找Bean的名字為* Target 的類,進(jìn)行方法過濾。呵呵,可能你會說這個有什么用?自己寫不也一樣么?其實如果系統(tǒng)變得龐大的話,自己配置也是十分耗費精力的。
     
    七. Spring-Aop DefaultAdvisorAutoProxyCreator
     
         接下來我們將介紹更加強(qiáng)大的一個代理器:DefaultAdvisorAutoProxyCreator。
         DefaultAdvisorAutoProxyCreator BeanNameAutoProxyCreator不同的是,DefaultAdvisorAutoProxyCreator只和Advisor 匹配,所以我們寫一個Advisor到xml文檔中去。
         XML 文檔如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
    <beans>
     
         <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
         <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
              <constructor-arg>
                   <value>5000</value>
              </constructor-arg>
         </bean>
     
         <!-- 使用RegexpMethodPointcutAdvisor來匹配切入點完成個一個Advisor; -->
         <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
              <property name="pattern">
                   <!--    
                        匹配的名字為方法名;
                   -->
                   <value>.*buy.*</value>
              </property>
              <property name="advice">
                   <ref bean="performanceThresholdInterceptor"/>
              </property>
         </bean>
     
         <bean id="defaultAdvisorAutoProxyCreator"
         class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
     
    </beans>
        
         添加下面方法調(diào)用main方法中去:
    /**
    * 創(chuàng)建defaultAdvisorAutoProxyCreator動態(tài)代理;
    */
       public static void defaultAdvisorProxy() {
     
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/defaultAdvisorProxy.xml");
     
            KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
            try {
                 akem.buyCheese(new Customer());
            } catch (KwikEMartException e) {
                 e.printStackTrace();
            }
       }
         運行,結(jié)果如下:
             
    開始測試時間.
    -- 我想買:奶酪!
    測試時間結(jié)束.
     
     
    八. Spring-Aop TargetSources 介紹
     
    1. 可熱交換的目標(biāo)源
     
    可熱交換的目標(biāo)源主要是在你程序運行中切換目標(biāo)對象,而此時調(diào)用者引用的對象也會自動切換。具體的概念你可以參考Spring-Reference關(guān)于它的介紹,我們主要在程序中體會它給我們帶來的改變。
    修改我們的xml成為下面的樣子:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
     
    <beans>
     
         <bean id="kwikEMartTarget" class="demo.ApuKwikEMart" ></bean>
        
         <bean id="swapApuKwikEMart" class="demo.SwapApuKwikEMart" singleton="false"></bean>
        
         <bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
     
         <bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
              <property name="mappedName">
                   <value>buy*</value>
              </property>
         </bean>
     
         <bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
              <property name="pointcut">
                   <ref bean="nameMatchfilterPointcut" />
              </property>
              <property name="advice">
                   <ref bean="onePerCustomerInterceptor" />
              </property>
         </bean>
     
         <bean id="swappable" class="org.springframework.aop.target.HotSwappableTargetSource">
              <constructor-arg><ref local="kwikEMartTarget"/></constructor-arg>
         </bean>
     
         <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="proxyInterfaces" value="demo.KwikEMart" />
              <property name="interceptorNames">
                   <list>
                        <value>runDemofilterPointcutAdvisor</value>
                   </list>
              </property>
              <property name="targetSource">
                   <ref bean="swappable" />
              </property>
         </bean>
     
    </beans>
     
    代碼:
    切換后的對象
    public class SwapApuKwikEMart implements KwikEMart {
         private boolean cheeseIsEmpty = false;
     
         private boolean pepperIsEmpty = false;
     
         private boolean squishIsEmpty = false;
     
         public Cheese buyCheese(Customer customer) throws KwikEMartException {
     
              if (cheeseIsEmpty) {
                   throw new NoMoreCheeseException();
              }
     
              Cheese s = new Cheese();
              System.out.println("-- 我不是ApuKwikEMart,我想買:" + s);
              return s;
     
         }
     
         public Pepper buyPepper(Customer customer) throws KwikEMartException {
     
              if (pepperIsEmpty) {
                   throw new NoMorePepperException();
              }
     
              Pepper s = new Pepper();
              System.out.println("-- 我不是ApuKwikEMart,我想買:" + s);
              return s;
     
         }
     
         public Squish buySquish(Customer customer) throws KwikEMartException {
     
              if (squishIsEmpty) {
                   throw new NoMoreSquishException();
              }
     
              Squish s = new Squish();
              System.out.println("-- 我不是ApuKwikEMart,我想買:" + s);
              return s;
     
         }
     
         public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
              this.cheeseIsEmpty = cheeseIsEmpty;
         }
     
         public void setPepperIsEmpty(boolean pepperIsEmpty) {
              this.pepperIsEmpty = pepperIsEmpty;
         }
     
         public void setSquishIsEmpty(boolean squishIsEmpty) {
              this.squishIsEmpty = squishIsEmpty;
         }
     
    }
    添加下面代碼的引用到我們的main中。
     /**
      * 熱源切換;
      */
     public static void swapKwikEMart() {
     
          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/swapKwikmart.xml");
     
          // 如果你想通過類來引用這個的話,就要用到CGLIB.jar了,同時在代理工廠里面設(shè)置:
          //<property name="proxyTargetClass" value="true" />
          KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
         
          try {
               akem.buySquish(new Customer());
               akem.buyPepper(new Customer());
               akem.buyCheese(new Customer());
          } catch (KwikEMartException e) {
               // 異常已經(jīng)被截獲了,不信你看控制臺!~;
          }
         
          HotSwappableTargetSource swap = (HotSwappableTargetSource) context.getBean("swappable");
          swap.swap(context.getBean("swapApuKwikEMart"));
         
          try {
               akem.buySquish(new Customer());
               akem.buyPepper(new Customer());
               akem.buyCheese(new Customer());
          } catch (KwikEMartException e) {
               // 異常已經(jīng)被截獲了,不信你看控制臺!~;
          }
     }
     
    運行,結(jié)果如下:
     
    店員:悠~游! ,Can I help you ?
    -- 我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    -- 我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    -- 我想買:奶酪!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    -- 我不是ApuKwikEMart,我想買:果醬!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    -- 我不是ApuKwikEMart,我想買:胡椒粉!
    店員:OK! 悠~游!.give you!
    店員:悠~游! ,Can I help you ?
    -- 我不是ApuKwikEMart,我想買:奶酪!
                                店員:OK! 悠~游!.give you!
     
    可以看到,我們切換后的對象已經(jīng)被置換了。注意 singleton="false" ,通常情況下需要設(shè)置為false,以保證Spring在必要的時候可以創(chuàng)建一個新的目標(biāo)實例。
     
    2. 支持池的目標(biāo)源
    使用支持目標(biāo)池的源提供了一種和無狀態(tài) session Ejb 類似的編程方式,在無狀態(tài)的 Session Ejb 中,維護(hù)了一個相同實例的池,提供從池中獲取可用對象的方法。
    這次我們用到了 Commons pool 這個包,同時在運行時候還需要 commons-collections.jar, 需要把它們加載到環(huán)境變量中。
    xml 文件如下:
     
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
     
     
    <beans>
     
         <bean id="kwikEMartTarget" class="demo.ApuKwikEMart" singleton="false"></bean>
     
         <bean id="commonsPool" class="org.springframework.aop.target.CommonsPoolTargetSource">
              <property name="targetBeanName">
                   <value>kwikEMartTarget</value>
              </property>
              <property name="maxSize">
                   <value>10</value>
              </property>
         </bean>
     
         <bean id="methodInvokingFactoryBeanAdvisor"
              class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
              <property name="targetObject">
                   <ref bean="commonsPool" />
              </property>
              <property name="targetMethod">
                   <value>getPoolingConfigMixin</value>
              </property>
     
         </bean>
         <bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
              <property name="proxyInterfaces" value="demo.KwikEMart" />
              <property name="interceptorNames">
                   <list>
                        <value>methodInvokingFactoryBeanAdvisor</value>
                   </list>
              </property>
              <property name="targetSource">
                   <ref bean="commonsPool" />
              </property>
         </bean>
     
    </beans>
     
    同時,我們還需要 添加下面代碼的引用到我們的main中。
    代碼:
     
           /**
            * 調(diào)用池對象;
            */
           public static void getCommonPoolObject() {
     
                  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");
     
                  KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");
                  try {
                         akem.buyCheese(new Customer());
                  } catch (KwikEMartException e) {
                         e.printStackTrace();
                  }
                 
                  PoolingConfig pool=(PoolingConfig)akem;
                  System.out.println(" 池的大小為: "+pool.getMaxSize());
           }
     
    運行,結(jié)果如下:
     
    -- 我想買:奶酪!
    池的大小為:10
     
    同時在我們的控制臺里可以看到這句話:
    信息: Creating Commons object pool
    你可以得到對象,也可以銷毀對象。但是必須你的目標(biāo)對象實現(xiàn)了 DisposableBean 接口,重寫銷毀的方法。然后通過下面方法調(diào)用:
     
    CommonsPoolTargetSource comPool = (CommonsPoolTargetSource) context.getBean("commonsPool");
     
    try {
           comPool.destroyObject(akem);
    } catch (Exception e) {
           e.printStackTrace();
                  }
    銷毀池則用:
    comPool.destroy()
                 
     
    九. Spring-Aop 相關(guān)及其他
     
    其他相關(guān)的比較重要的是org.springframework.aop.framework.ProxyFactoryBean 類,幾乎我們上篇都用到了這個類,簡單介紹一下:
     

    ProxyFactoryBean

    屬性
    描述
    target
    代理的目標(biāo)對象
    proxyInterfaces
    代理實現(xiàn)的接口
    interceptorNames
    在應(yīng)用到的目標(biāo)對象上添加的Advice的名字,可以是攔截器、advisor或者其他通知類型的名字(順序很重要哦)
     
    其他還有singleton,proxyTargetClass。
    singleton :每次調(diào)用getBean()的時候返回一個新的實例,例如我們使用引入的時候,有狀態(tài)的bean要設(shè)置為false哦。
         proxyTargetClass :是否代理目標(biāo)類,而不是實現(xiàn)接口。只能在使用CBLIB的時使用。
        
    proxyTargetClass 重點說一下,什么意思呢?白話說的意思就是:如果你不設(shè)置proxyInterfaces這個,就必須設(shè)置這個方法,并且方法值為True。就是告訴CBLIB你要動態(tài)創(chuàng)建一個代理類來引用我們的目標(biāo)。
             
    Spring-Reference 中,提到了事務(wù)代理,我想那個相對于持久化處理時候在了解比較合適。 對于元數(shù)據(jù)的支持,因為我還沒有精力讀到哪里。所以這個暫且擱下,有興趣的讀者可以自己查閱參考。
     
    非常感謝你能讀完正篇文章,將不足的地方通過郵件傳遞給我,我將盡快改正。最后我希望,能夠讓每一個讀過的人都有所獲得,讓我們享受Spring給我們帶來的樂趣吧。
     
       
       
        參考資料;
                   Spring-Reference 中文版 第五章 Spring 之面向方面編程  
                                                                         http://www.jactiongroup.net/reference/html/
            
    Spring AOP 中文教程                                http://spring.jactiongroup.net/viewtopic.php?t=478
        
    Spring In Action 中文版 第三章
        
    AOP 入門

    posted on 2006-12-19 13:17 常言笑 閱讀(731) 評論(0)  編輯  收藏 所屬分類: JAVA/J2EE

    My Links

    Blog Stats

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 免费91麻豆精品国产自产在线观看 | 久久国产精品免费| 国产伦一区二区三区免费| 亚洲AV成人无码天堂| 99久久国产免费-99久久国产免费 99久久国产免费中文无字幕 | 亚洲色欲或者高潮影院| 222www免费视频| 亚洲国产日韩在线| 国产h视频在线观看免费| 亚洲午夜电影在线观看高清| 午夜国产精品免费观看 | 中文字幕av免费专区| 亚洲日本乱码在线观看| 日本视频在线观看永久免费 | 亚洲国产精品成人久久久| 国拍在线精品视频免费观看| 亚洲一区二区三区乱码在线欧洲| 成人在线免费观看| 国产亚洲综合视频| 亚洲午夜无码久久久久| 久久国产精品免费网站| 亚洲免费中文字幕| 免费看国产一级特黄aa大片| 国产高清对白在线观看免费91| 亚洲国产成人精品无码区在线观看| 高清一区二区三区免费视频| 亚洲国色天香视频| 免费观看国产小粉嫩喷水| 伊人免费在线观看| 亚洲欧洲日产国码二区首页| 热久久精品免费视频| 亚洲免费一区二区| 亚洲精品视频在线免费| 国产极品美女高潮抽搐免费网站| 一个人看的www在线免费视频| 91亚洲导航深夜福利| 国产精品嫩草影院免费| 香港a毛片免费观看| 亚洲国产成人久久综合| 亚洲成AV人在线观看天堂无码| 无码人妻精品中文字幕免费东京热|