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

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

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

    備注學(xué)院

    LuLu

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      5 隨筆 :: 50 文章 :: 16 評(píng)論 :: 0 Trackbacks

    有時(shí)候我們要跟蹤方法的執(zhí)行時(shí)間,來(lái)觀察系統(tǒng)的性能、時(shí)間分布。特別是要找出那些十分耗時(shí)的操作。如果是在每個(gè)方法中起始和結(jié)束位置記下時(shí)間相減,那是不太現(xiàn)實(shí)的,對(duì)代碼的侵入性太過(guò)份,而且在產(chǎn)品環(huán)境中又得屏閉那部份代碼。

    幸好現(xiàn)在有了 AOP,通過(guò)配置方式再加上外部輔助代碼就能達(dá)到我們的要求,正式上線時(shí)只需要簡(jiǎn)單改個(gè)配置項(xiàng)拆卸下來(lái)即可。

    下面介紹三種方式來(lái)打印每個(gè)方法的執(zhí)行時(shí)間,分別是:

    1. Spring 2.0 用 AspectJ 實(shí)現(xiàn) AOP
    2. Spring 通用的方法攔截
    3. 直接用 AspectJ 實(shí)現(xiàn)


    1. Spring 2.0 用 AspectJ 實(shí)現(xiàn) AOP

    這個(gè)實(shí)例由五個(gè)文件構(gòu)成,兩個(gè)配置文件和三個(gè)類文件。需要在項(xiàng)目中引用 Spring 2.0 以上版本的相關(guān)包,還要日志包。

    1) log4j.properties  放在 src 目錄下

    1. log4j.rootLogger=DEBUG,stdout   
    2.   
    3. log4j.appender.stdout=org.apache.log4j.ConsoleAppender    
    4. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout    
    5.   
    6. log4j.appender.stdout.layout.ConversionPattern=%d [%5p] %c{1}.%M(%L) %n%m%n   

    2) applicationContext.xml   放在 src 目錄下

    1. <beans xmlns="http://www.springframework.org/schema/beans"  
    2.       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    3.       xmlns:aop="http://www.springframework.org/schema/aop"  
    4.       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd   
    5. http://www.spridngframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
    6.   
    7.     <aop:config>  
    8.         <!-- Spring 2.0 可以用 AspectJ 的語(yǔ)法定義 Pointcut,這里攔截 service 包中的所有方法 -->  
    9.         <aop:advisor id="methodTimeLog" advice-ref="methodTimeAdvice" pointcut="execution(* *..service..*(..))"/>  
    10.     </aop:config>  
    11.   
    12.     <bean id="methodTimeAdvice" class="com.unmi.util.MethodTimeAdvice"/>  
    13.     <bean id="helloService" class="com.unmi.service.HelloService"/>  
    14. </beans>  

    3) MethodTimeAdvice.java 記錄時(shí)間的類

    1. package com.unmi.util;   
    2.   
    3. import org.aopalliance.intercept.MethodInterceptor;   
    4. import org.aopalliance.intercept.MethodInvocation;   
    5. import org.apache.commons.lang.StringUtils;   
    6. import org.apache.commons.lang.time.StopWatch;   
    7. import org.apache.commons.logging.Log;   
    8. import org.apache.commons.logging.LogFactory;   
    9.   
    10. /**  
    11.  * 記錄方法的執(zhí)行時(shí)間  
    12.  * @author Unmi  
    13.  */  
    14. public class MethodTimeAdvice implements MethodInterceptor {   
    15.     protected final Log log = LogFactory.getLog(MethodTimeAdvice.class);   
    16.   
    17.     /**  
    18.      * 攔截要執(zhí)行的目標(biāo)方法  
    19.      */  
    20.     public Object invoke(MethodInvocation invocation) throws Throwable {   
    21.         //用 commons-lang 提供的 StopWatch 計(jì)時(shí),Spring 也提供了一個(gè) StopWatch   
    22.         StopWatch clock = new StopWatch();   
    23.         clock.start(); //計(jì)時(shí)開始   
    24.         Object result = invocation.proceed();   
    25.         clock.stop();  //計(jì)時(shí)結(jié)束   
    26.            
    27.         //方法參數(shù)類型,轉(zhuǎn)換成簡(jiǎn)單類型   
    28.         Class[] params = invocation.getMethod().getParameterTypes();   
    29.         String[] simpleParams = new String[params.length];   
    30.         for (int i = 0; i < params.length; i++) {   
    31.             simpleParams[i] = params[i].getSimpleName();   
    32.         }   
    33.            
    34.         log.debug("Takes:" + clock.getTime() + " ms ["  
    35.                 + invocation.getThis().getClass().getName() + "."  
    36.                 + invocation.getMethod().getName() + "("+StringUtils.join(simpleParams,",")+")] ");   
    37.         return result;   
    38.     }   
    39. }  

    4) HelloService.java 被攔截的業(yè)務(wù)類

    1. package com.unmi.service;   
    2.   
    3. /**  
    4.  * @author Unmi  
    5.  */  
    6. public class HelloService {   
    7.     public void sayHello(int id,String name){   
    8.         try {   
    9.             Thread.sleep(512);   
    10.         } catch (InterruptedException e) {   
    11.             e.printStackTrace();   
    12.         }   
    13.         System.out.println("Hello "+name+"("+id+")");   
    14.     }   
    15. }  

    5) Main.java 主程序類

    1. package com.unmi;   
    2.   
    3. import org.springframework.beans.factory.BeanFactory;   
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;   
    5.   
    6. import com.unmi.service.HelloService;   
    7.   
    8. /**  
    9.  * 測(cè)試主類  
    10.  * @author Unmi  
    11.  */  
    12. public class Main {   
    13.   
    14.     /**  
    15.      * @param args  
    16.      */  
    17.     public static void main(String[] args) {   
    18.         BeanFactory factory =new ClassPathXmlApplicationContext("applicationContext.xml");   
    19.         HelloService helloService = (HelloService)factory.getBean("helloService");   
    20.         helloService.sayHello(1,"Unmi");   
    21.     }   
    22. }  

    執(zhí)行 Main 后輸出的結(jié)果是:

     Hello Unmi(1)
    2008-01-18 13:41:25,593 [DEBUG] MethodTimeAdvice.invoke(34)
    Takes:516 ms [com.unmi.service.HelloService.sayHello(int,String)]

     

    如果不需要這個(gè)功能,只要在 applicationContext.xml 中把 id="methodTimeLog" 和 id="methodTimeAdvice" 配置項(xiàng)注釋掉就行了。

    2. Spring 通用的方法攔截

    Spring 1.x 因?yàn)椴荒苡?AspectJ 來(lái)對(duì)方法進(jìn)行攔截,要用到 ProxyFactoryBean 使用 AOP,具體操作方法只需要更換以上例子中的 applicationContext.xml 文件就行,內(nèi)容如下:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
    3.      "http://www.springframework.org/dtd/spring-beans.dtd">  
    4. <beans>  
    5.   
    6.     <bean id="methodTimeAdvice" class="com.unmi.util.MethodTimeAdvice"/>  
    7.     <bean id="helloServiceTarget" class="com.unmi.service.HelloService"/>  
    8.        
    9.     <bean id="methodTimeAdvisor"  
    10.         class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">    
    11.         <property name="advice">  
    12.             <ref bean="methodTimeAdvice"/>    
    13.         </property>    
    14.         <!--對(duì)指定類的任何方法有效-->  
    15.         <property name="patterns">    
    16.             <value>.*.*</value>    
    17.         </property>    
    18.     </bean>  
    19.        
    20.     <bean id="helloService" class="org.springframework.aop.framework.ProxyFactoryBean">  
    21.         <property name="interceptorNames">  
    22.             <list>  
    23.                 <value>methodTimeAdvisor</value>  
    24.             </list>  
    25.         </property>  
    26.         <property name="target">  
    27.             <ref bean="helloServiceTarget"/>  
    28.         </property>  
    29.     </bean>  
    30.        
    31. </beans>  


    上面的配置方式需為每個(gè)應(yīng)用方法執(zhí)行時(shí)間記錄的 Bean 在外層包一個(gè) ProxyFactoryBean,原來(lái)的 Bean 設(shè)為一個(gè) Target 實(shí)在時(shí)麻煩了。

    下面用一種應(yīng)用自動(dòng)代理的配置方式,指定 BeanNameAutoProxyCreator 的 beanNames 匹配模式即可,如果寫成 <value>*Service,*Manager</value>,逗號(hào)分隔開,以 Service 或 Manager 結(jié)層類的方法都被攔截,這樣方便許多。

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
    3.      "http://www.springframework.org/dtd/spring-beans.dtd">  
    4. <beans>  
    5.   
    6.     <bean id="methodTimeAdvice" class="com.unmi.util.MethodTimeAdvice" />  
    7.     <bean id="helloService" class="com.unmi.service.HelloService" />  
    8.   
    9.     <bean id="methodTimeAdvisor"  
    10.         class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    11.         <property name="advice">  
    12.             <ref bean="methodTimeAdvice" />  
    13.         </property>  
    14.         <!--對(duì)指定類的任何方法有效-->  
    15.         <property name="patterns">  
    16.             <value>.*.*</value>  
    17.         </property>  
    18.     </bean>  
    19.   
    20.     <!-- 根據(jù) Bean 的名字自動(dòng)實(shí)現(xiàn)代理攔截 -->  
    21.     <bean  
    22.         class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
    23.         <property name="interceptorNames">  
    24.             <list>  
    25.                 <value>methodTimeAdvisor</value>  
    26.             </list>  
    27.         </property>  
    28.         <property name="beanNames">  
    29.             <list>  
    30.                 <!-- 添加到其中的 Bean 自動(dòng)就被代理攔截了 -->  
    31.                 <value>*Service</value>  
    32.             </list>  
    33.         </property>  
    34.     </bean>  
    35. </beans>  


    3. 直接用 AspectJ 實(shí)現(xiàn)

    AspectJ 提供了一套語(yǔ)法來(lái)定義切面,Spring 2.0 開始引入了 AspectJ 的部分功能,但如果要用上 AspectJ 更多強(qiáng)大完善的功能,諸如實(shí)例構(gòu)造時(shí),屬性被訪問時(shí),動(dòng)態(tài)改變類定義,滋生新的屬性、方法,更強(qiáng)基于流程的控制時(shí),恐怕非得顯式的使用 AspectJ。當(dāng)然,首先你得去 http://www.eclipse.org/aspectj/ 下載到 AspectJ 或者 AspectJ 的 Eclipse 插件。本人強(qiáng)烈建議使用 AspectJ 的 Eclipse 插件,請(qǐng)下載相應(yīng) Eclipse 版本的 AspectJ 插件,Eclipse 3.3 要搭配 AJDT: The AspectJ Development Tools 1.5。不要插件的話就得命令行下 ajc 編譯你的方面,不容易習(xí)慣的。 

    AJDT 安裝成功后,你可以新建 AspectJ 項(xiàng)目,或者把前面項(xiàng)目轉(zhuǎn)換成 AspectJ 項(xiàng)目。從項(xiàng)目的上下文菜單中可以看到 AspectJ Tools -> Convert to Aspectj Project。然后在包 com.unmi.util 中新建一個(gè)方面,包 com.unmi.util 的上下文菜單中 New -> Aspect,輸入名字 MethodTimeAdviceRecipe,然后 Finish,這時(shí)就會(huì)在包 com.unmi.util 中產(chǎn)生一個(gè)文件 MethodTimeAdviceRecipe.aj,內(nèi)容如下:

    MethodTimeAdviceRecipe.aj (那么 MethodTimeAdvice.java 就派不上用場(chǎng)了,可刪去)

    1. package com.unmi.util;   
    2. import org.apache.commons.lang.time.StopWatch;   
    3. import org.apache.commons.logging.Log;   
    4. import org.apache.commons.logging.LogFactory;   
    5.   
    6.   
    7. /**  
    8.  * 記錄方法的執(zhí)行時(shí)間  
    9.  * @author Unmi  
    10.  */  
    11. public aspect MethodTimeAdviceRecipe {   
    12.        
    13.     protected final Log log = LogFactory.getLog(MethodTimeAdvice.class);   
    14.        
    15.     //攔截所有以 Service 結(jié)尾類的方法   
    16.     pointcut callServicePointCut() : call(* *..*Service.*(..))   
    17.                                         && !within(MethodTimeAdviceRecipe +);   
    18.        
    19.     /**  
    20.      * 在方連接點(diǎn)(業(yè)務(wù)類方法)周圍執(zhí)行的通知  
    21.      */  
    22.     Object around() : callServicePointCut(){   
    23.         //用 commons-lang 提供的 StopWatch 計(jì)時(shí),Spring 也提供了一個(gè) StopWatch   
    24.         StopWatch clock = new StopWatch();   
    25.         clock.start(); //計(jì)時(shí)開始   
    26.         Object result = proceed();   
    27.         clock.stop();  //計(jì)時(shí)結(jié)束   
    28.            
    29.         //顯示出方法原型及耗時(shí)   
    30.         log.debug("Takes: " + clock.getTime() + " ms ["+thisJoinPoint.getSignature()+"("+   
    31.                 thisJoinPoint.getSourceLocation().getLine()+")]");   
    32.            
    33.         return result;   
    34.     }   
    35. }  

    再就是因?yàn)闊o(wú)需用到 Spring 了,不需要 IOC 了,相應(yīng)的 Main.java 的內(nèi)容如下:

    Main.java (以前如何創(chuàng)建 HelloService,現(xiàn)在還是怎么做)

    1. package com.unmi;   
    2.   
    3. import com.unmi.service.HelloService;   
    4.   
    5. /**  
    6.  * 測(cè)試主類  
    7.  * @author Unmi  
    8.  */  
    9. public class Main {   
    10.   
    11.     /**  
    12.      * @param args  
    13.      */  
    14.     public static void main(String[] args) {   
    15.         HelloService helloService = new HelloService();   
    16.         helloService.sayHello(1,"Unmi");   
    17.     }   
    18. }  

    OK,現(xiàn)在就可以在 Eclipse 中開始運(yùn)行 Main 類了,對(duì) methodTimeAdviceRecipe.aj 的編譯工作由插件 AJDT 自動(dòng)幫你作了(實(shí)質(zhì)是相匹配的類中插入了代碼)。運(yùn)行 Main 的結(jié)果如下:

    Hello Unmi(1)
    2008-01-21 13:48:16,171 [DEBUG] MethodTimeAdvice.sayHello_aroundBody1$advice(130)
    Takes: 515 ms [void com.unmi.service.HelloService.sayHello(int, String)(16)]


    用 AspectJ 可以很靈活的定義方面,局限就是對(duì)方面的改變須重新編譯相關(guān)類,而非配置方式。

    參考:一個(gè)用Spring AOP實(shí)現(xiàn)異常處理和記錄程序執(zhí)行時(shí)間的實(shí)例

     


    FORM:http://m.tkk7.com/Unmi/archive/2008/01/18/165849.html
    posted on 2008-02-04 22:56 smildlzj 閱讀(704) 評(píng)論(0)  編輯  收藏 所屬分類: JavaWeb開發(fā)
    主站蜘蛛池模板: 久久精品亚洲一区二区| 亚洲午夜久久久久久噜噜噜| 亚洲欧洲日本精品| 99re在线这里只有精品免费| 亚洲国产精品无码久久SM| 99久久免费国产特黄| 亚洲日本一区二区三区在线| 国产成人AV免费观看| 久久久亚洲精品视频| 8x网站免费入口在线观看| 亚洲男人第一av网站| 四虎永久在线精品免费观看视频| 亚洲电影在线免费观看| 国产免费av片在线看| 亚洲国产成人综合精品| 免费又黄又硬又爽大片| 精品熟女少妇aⅴ免费久久 | 久久国产乱子伦精品免费不卡| 亚洲va在线va天堂va不卡下载| 亚洲最大免费视频网| 亚洲综合无码无在线观看| 免费一级e一片在线播放| 成在线人免费无码高潮喷水| 亚洲AV福利天堂一区二区三| 美女网站免费福利视频| 黄页网站在线观看免费| 亚洲精品无码午夜福利中文字幕| 最新亚洲成av人免费看| 亚洲国产亚洲片在线观看播放| 色妞WWW精品免费视频| 日本激情猛烈在线看免费观看| 久久91亚洲人成电影网站| 一二三四影视在线看片免费 | 亚洲美女色在线欧洲美女| 女人被弄到高潮的免费视频| 一级做a爰片性色毛片免费网站| 久久精品国产99精品国产亚洲性色| 国产h视频在线观看网站免费| 在线观看亚洲电影| 亚洲AV无码久久精品色欲| 在线视频免费观看www动漫|