1. 程式人生 > >Spring AOP中的JDK動態代理

Spring AOP中的JDK動態代理

一、關於靜態代理和動態代理的概念1 代理模式是常用的Java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務。按照代理類的建立時期,代理類可分為兩種。 靜態代理類:由程式設計師建立或由特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。 動態代理類:在程式執行時,運用反射機制動態建立而成。 靜態代理通常只代理一個類,動態代理是代理一個介面下的多個實現類。 靜態代理事先知道要代理的是什麼,而動態代理不知道要代理什麼東西,只有在執行時才知道。 動態代理是實現JDK裡的InvocationHandler介面的invoke方法,但注意的是代理的是介面,也就是你的業務類必須要實現介面,通過Proxy裡的newProxyInstance得到代理物件。 還有一種動態代理CGLIB,代理的是類,不需要業務類繼承介面,通過派生的子類來實現代理。通過在執行時,動態修改位元組碼達到修改類的目的。 2、JDK動態代理 JDK的動態代理主要涉及java.lang.reflect包中的兩個類:Proxy類和InvocationHandler。其中,InvocationHandler是一個介面,可以通過實現介面定義橫切邏輯,並通過反射機制呼叫目標類的程式碼,動態地將橫切邏輯和業務邏輯編織在一起。 而Proxy利用InvocationHandler動態建立一個符合某一介面的例項,生成目標類的代理物件。接下來用一個例子說明: (1)建立一個業務類ForumService

package com.changmin.proxy;

public interface ForumService {
    void removeTopic(int topicId);
    void removeForum(int forumId);
}

(2)建立一個帶有橫切邏輯的例項

package com.changmin.proxy;

public class ForumServiceImpl implements ForumService {

    public void removeTopic(int topicId) {
 		//PerformanceMonitor.begin("com.changmin.proxy.ForumServiceImpl.removeTopic");
        System.out.println("模擬刪除Topic記錄:"+topicId);
        try {
            Thread.currentThread().sleep(20);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
 		//PerformanceMonitor.end();
    }

    public void removeForum(int forumId) {
 		//PerformanceMonitor.begin("com.changmin.proxy.ForumServiceImpl.removeForum");
        System.out.println("模擬刪除Forum記錄:"+forumId);
        try {
            Thread.currentThread().sleep(40);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
 		//PerformanceMonitor.end();
    }
}

每一個Service類和每個業務方法體前後都執行相同的程式碼邏輯:方法呼叫前啟動PerformanceMonitor.begin();方法呼叫後啟動PerformanceMonitor.end()結束效能監視。 (3)建立效能監視的實現類PerformanceMonitor

package com.changmin.proxy;

public class PerformanceMonitor {
    private static ThreadLocal<MethodPerformace> performaceRecord = new ThreadLocal<MethodPerformace>();
    public static void begin(String method) {
        System.out.println("begin monitor...");
        MethodPerformace mp = performaceRecord.get();//獲取performanceRecord中當前執行緒共享變數的值。
        if(mp == null){
            mp = new MethodPerformace(method);
            performaceRecord.set(mp);
        }else{
            mp.reset(method);
        }
    }
    public static void end() {
        System.out.println("end monitor...");
        MethodPerformace mp = performaceRecord.get();
        mp.printPerformace();
    }
}

(4)建立PerformanceHandler類用於安置效能監視橫切程式碼

package com.changmin.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformaceHandler implements InvocationHandler {                      //實現InvocationHandler介面
    private Object target;                                                          //宣告Object類物件target
    public PerformaceHandler(Object target){
        this.target = target;
    }              //設定PerformanceHandler類的target屬性
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
        Object obj = method.invoke(target, args);                                    //輸出引數為args的target()方法的返回值,賦予obj
        PerformanceMonitor.end();
        return obj;
    }
}

(5)建立代理例項並測試

package com.changmin.proxy;

import org.testng.annotations.Test;

public class ForumServiceTest {
    @Test
    public void proxy() {
        // 使用JDK動態代理
		ForumService target = new ForumServiceImpl();
		PerformaceHandler handler = new PerformaceHandler(target);
		ForumService proxy = (ForumService) Proxy.newProxyInstance(target
				.getClass().getClassLoader(),
				target.getClass().getInterfaces(), handler);
		proxy.removeForum(10);
		proxy.removeTopic(1012);
    }
}

(6)執行結果

begin monitor...
模擬刪除Forum記錄:10
end monitor...
com.changmin.proxy.ForumServiceImpl.removeForum花費46毫秒。
begin monitor...
模擬刪除Topic記錄:1012
end monitor...
com.changmin.proxy.ForumServiceImpl.removeTopic花費32毫秒。