JDK動態代理

    JDK 1.3以後,java提供了動態代理的技術,允許開發者在運行初期創建接口的代理實例。所謂代理即對某一實例的增強,對象在實例化的時候得到增強,增強過的實例即爲代理實例,代理實例往往在運行的時候被動態增強。

    JDK的動態代理主要涉及到java.lang.reflect包中的兩個類:Proxy和InvocationHandler。其中InvocationHandler是一個接口,可以通過實現該接口定義橫切邏輯,並通過反射機制調用目標類代碼,動態地將橫切邏輯和業務邏輯編織在一起。

    而Proxy利用InvocationHandler動態創建一個符合某一接口的實例,生成目標類的代理對象。下面通過一組實例演示如何使用JDK的動態代理。

FormService.java

public interface FormService {

	/**
	 * 模擬論壇話題被刪除
	 * @param topicId
	 */
	public void removeTopic(int topicId);
	/**
	 * 模擬論壇被刪除
	 * @param forumId
	 */
	public void removeForum(int forumId);
}

FormServiceImpl.java

public class FormServiceImpl implements FormService {

	@Override
	public void removeTopic(int topicId) {
		System.out.println("模擬刪除Topic記錄:" + topicId);
		try {
			Thread.sleep(20);
		} catch (InterruptedException e) {
			throw new RuntimeException();
		}
	}

	@Override
	public void removeForum(int forumId) {
		System.out.println("模擬刪除Topic記錄:" + forumId);
		try {
			Thread.sleep(40);
		} catch (InterruptedException e) {
			throw new RuntimeException();
		}
	}

}

PerformanceHandler.java

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

public class PerformanceHandler implements InvocationHandler {

	private Object target;
	public PerformanceHandler(Object target) {
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] params)
			throws Throwable {
		String methodName = target.getClass().getName() + "." + method.getName();
		System.out.println("對" + methodName + "方法進行性能檢測。");
		long start = System.currentTimeMillis();
		Object obj = method.invoke(target, params);
		long end = System.currentTimeMillis();
		System.out.println(methodName +"方法用時:" + (end - start) + "毫秒。");
		return obj;
	}

}

測試類TestForProxy.java

import java.lang.reflect.Proxy;
public class TestForProxy {
	public static void main(String[] args) {
		FormService forumService = new FormServiceImpl();
		PerformanceHandler handler = new PerformanceHandler(forumService);
		FormService proxy = (FormService) Proxy.newProxyInstance(
				forumService.getClass().getClassLoader(),
				forumService.getClass().getInterfaces(),handler);
		proxy.removeForum(10);
		proxy.removeTopic(1012);
	}
}

程序運行運行結果:

對org.proxy.jdkproxy.FormServiceImpl.removeForum方法進行性能檢測。
模擬刪除Topic記錄:10
org.proxy.jdkproxy.FormServiceImpl.removeForum方法用時:40毫秒。
對org.proxy.jdkproxy.FormServiceImpl.removeTopic方法進行性能檢測。
模擬刪除Topic記錄:1012
org.proxy.jdkproxy.FormServiceImpl.removeTopic方法用時:20毫秒。

    在以上代碼中,我們實現了InvocationHandler接口,該接口定義了一個invoke(Object proxy,Method method,Object[] params)的方法,proxy是最終生成的代理實例,一般不會用到;method是被代理目標實例的某個具體方法,通過他可以發起目標實例方法的反射調用;params是通過被代理實例某一具體方法的入參,在方法反射時使用它。

    注意:JDK的動態代理是針對接口的代理,即增強目標類必須是實現了某一個或多個接口的類,其被增強的方法也必須是接口中的方法,之所以稱之爲動態代理是因爲對實例的代理髮生在運行期,另外代理還可以發生在編譯期和裝載期(需要特殊的編譯器和裝載器)。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章