動態代理(如下稱代理),利用Java的反射技術(Java Reflection),在運行時建立一個實現某些給定接口的新類(也稱「動態代理類」)及其實例(對象)html
(Using Java Reflection to create dynamic implementations of interfaces at runtime)。java
代理的是對象是接口(Interfaces),不是類(Class),更不是抽象類。git
解決特定問題:一個接口的實如今編譯時沒法知道,須要在運行時才能實現github
實現某些設計模式:適配器(Adapter)或修飾器(Decorator)編程
面向切面編程:如AOP in Spring.設計模式
利用Java的Proxy類,調用Proxy.newProxyInstance(),api
而Proxy.newProxyInstance()方法有三個參數:數組
1. 類加載器(Class Loader);緩存
2. 須要實現的接口數組;oracle
3. InvocationHandler接口,全部動態代理類的方法調用,都會交由InvocationHandler接口實現類裏的invoke()方法去處理。這是動態代理的要義所在。
下面是官方文檔解釋:
ublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler. This method is equivalent to:
Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
Proxy.newProxyInstance
throws IllegalArgumentException
for the same reasons that Proxy.getProxyClass
does.
Parameters:
loader
- the class loader to define the proxy class
interfaces
- the list of interfaces for the proxy class to implement
h
- the invocation handler to dispatch method invocations to
Returns:
a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces
Throws:
IllegalArgumentException
- if any of the restrictions on the parameters that may be passed to getProxyClass
are violated
NullPointerException
- if the interfaces
array argument or any of its elements are null
, or if the invocation handler, h
, is null
接口裏有一個invoke()方法。基本的作法是,建立一個類,實現這個方法,利用反射在invoke()方法裏實現需求:
public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //do something "dynamic" } }
invoke()方法也一樣有三個參數:
1. 動態代理類的引用,一般狀況下不須要它。但可使用getClass()方法,獲得proxy的Class類從而取得實例的類信息,如方法列表,annotation等。
2. 方法對象的引用,表明被動態代理類調用的方法。從中可獲得方法名,參數類型,返回類型等等。
3. args對象數組,表明被調用方法的參數。注意基本類型(int,long)會被裝箱成對象類型(Interger, Long)。
//interface public interface DynamicQuiz { void run(); } //do something public class DynamicProxyTest implements DynamicQuiz { @Override public void run() { System.out.println("this is a dynmic quiz"); } } //proxy process class DynamicProxy implements InvocationHandler { DynamicQuiz dynamicQuiz; DynamicProxy() { } DynamicQuiz bind(DynamicQuiz dynamicQuiz) { this.dynamicQuiz = dynamicQuiz; return (DynamicQuiz) Proxy.newProxyInstance(dynamicQuiz.getClass().getClassLoader(), dynamicQuiz.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("welcome"); Object result = method.invoke(dynamicQuiz, args); System.out.println("see you agin"); return result; } } //main public class Main { public static void main(String[] args) { DynamicQuiz dynamicQuiz = new DynamicProxyTest(); DynamicQuiz quizeResult = new DynamicProxy().bind(dynamicQuiz); quizeResult.run(); } }
從上面的代碼能夠看出,對DynamicQuiz接口的調用,會交由Proxy的invoke方法處理,並在不改變run()的源代碼下,新增了動態的邏輯(before running/after running),這正式AOP所作的。
深刻講,Proxy.newInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)作了如下幾件事.
(1)根據參數loader和interfaces調用方法 getProxyClass(loader, interfaces)建立代理類$Proxy.
$Proxy0類實現了interfaces的接口,並繼承了Proxy類.
(2)實例化$Proxy0並在構造方法中把BusinessHandler傳過去,接着$Proxy0調用父類Proxy的構造器,爲h賦值.
1.接口的run()會觸發invoke(), 因此在proxy裏面切不可將invoke()替換成(DynamicQuiz)poxy.run(),不然就形成死循環,形成棧溢出。
2.跟蹤源碼能夠看到,程序進行了驗證、優化、緩存、同步、生成字節碼、顯示類加載等操做,前面的步驟並非咱們關注的重點,而最後它調用了sun.misc.ProxyGenerator.generateProxyClass()方法完成生成字節碼的動做,這個方法能夠在運行時產生一個描述代理類的字節碼byte[]數組。若是想看這個運行時產生的代理類中的內容,能夠在main方法加以下這句代碼:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
運行會生成一個名爲"$Proxy).class"的代理class文件,反編譯以後就能看見內容。
代碼地址:https://github.com/wangtao1/dynamic
參考:
深刻理解java虛擬機第9章節
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
http://www.cnblogs.com/techyc/p/3455950.html