天天看點

Spring AOP 本質(4)

這一主要看看Spring AOP是如何實作通知包圍的。

Spring AOP包圍通知在功能上和前置通知加後置通知類似,但還是有差別的:包圍通知可以修改傳回值,還可以阻止、替換目标方法的執行。

Spring裡的包圍通知是實作MethodInterceptor接口的攔截器。

Spring包圍通知有着很廣泛的應用,比如遠端代理和事務管理,都是由攔截器完成。另外,攔截器也是剖析程式運作的好方法。

下面利用Spring AOP包圍通知實作監控業務方法的執行運作過程耗時情況。

/** 
* 業務元件 
*/ 
public class WorkerBean { 

    public void doSomeWork(int noOfTimes) { 
        for(int x = 0; x < noOfTimes; x++) { 
            work(); 
        } 
    } 
     
    private void work() { 
        System.out.print(""); 
    } 
} 
import java.lang.reflect.Method; 

import org.aopalliance.intercept.MethodInterceptor; 
import org.aopalliance.intercept.MethodInvocation; 
import org.springframework.util.StopWatch; 

/** 
* 攔截器,實作方法包圍通知 
*/ 
public class ProfilingInterceptor implements MethodInterceptor { 

    public Object invoke(MethodInvocation invocation) throws Throwable { 
        //啟動一個 stop watch 
        StopWatch sw = new StopWatch(); 
        //運作計時器 
        sw.start(invocation.getMethod().getName()); 
        //執行業務方法 
        Object returnValue = invocation.proceed(); 
        //停止計時器 
        sw.stop(); 
        //垃圾資訊輸出 
        dumpInfo(invocation, sw.getTotalTimeMillis()); 
        //傳回業務方法傳回值 
        return returnValue; 
    } 

    /** 
     * 垃圾資訊輸入方法,實際上輸出的是方法運作的計時資訊 
     */ 
    private void dumpInfo(MethodInvocation invocation, long ms) { 
        //擷取被調用方法 
        Method m = invocation.getMethod(); 
        //擷取被調用方法所屬的對象 
        Object target = invocation.getThis(); 
        //擷取被調用方法的參數 
        Object[] args = invocation.getArguments(); 

        System.out.println("所執行的方法: " + m.getName()); 
        System.out.println("對象的類型: " + target.getClass().getName()); 

        System.out.println("方法的參數:"); 
        for (int x = 0; x < args.length; x++) { 
            System.out.print("    > " + args[x]); 
        } 
        System.out.print("\n"); 

        System.out.println("抓取方法運作的時間: " + ms + " ms"); 
    } 
} 
import org.springframework.aop.framework.ProxyFactory; 

/** 
* 用戶端測試方法 
*/ 
public class ProfilingExample { 

    public static void main(String[] args) { 
        //建立代理對象 
        WorkerBean bean = getWorkerBean(); 
        //在代理對象上調用業務方法 
        bean.doSomeWork(10000000); 
    } 

    /** 
     * 代理對象工廠 
     */ 
    private static WorkerBean getWorkerBean() { 
        //建立目标對象 
        WorkerBean target = new WorkerBean(); 
        //建構代理對象工廠 
        ProxyFactory factory = new ProxyFactory(); 
        factory.setTarget(target); 
        factory.addAdvice(new ProfilingInterceptor()); 

        //生産一個代理對象 
        return (WorkerBean)factory.getProxy(); 
    } 
}      

運作結果:

- Using JDK 1.4 collections 

所執行的方法: doSomeWork 

對象的類型: com.apress.prospring.ch6.profiling.WorkerBean 

方法的參數: 

    > 10000000 

抓取方法運作的時間: 3453 ms 

Process finished with exit code 0

從輸出的結果中,可以看到程式方法調用的方法名、參數、所屬類,以及執行方法所耗費的時間。

另外說一下org.springframework.util.StopWatch類,這是個計時器類,此工具類主要可以擷取計時器類start()和stop()兩次方法調用間的時間。具體可以檢視Spring的API文檔。另外,我也在apache commons 包裡面也有org.apache.common.lang.time.StopWatch。

​​http://lavasoft.blog.51cto.com/62575/75342/​​