java反射機制與動態代理
在學習HadoopRPC時,用到了函數調用,函數調用都是采用的java的反射機制和動態代理來實現的,所以現在回顧下java的反射和動態代理的相關知識。
一、反射
JAVA反射機制定義: JAVA反射機制是java程序在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
反射就是把Java類中的各種成分映射成相應的Java類。
Java反射機制主要提供了以下功能:
1、在運行時判斷任意一個對象所屬的類;
2、在運行時構造任意一個類的對象;
3、在運行時判斷任意一個類所具有的成員變量和方法;
4、在運行時調用任意一個對象的方法;
5、生成動態代理。
我們了解了反射機制的功能,那么我們如何具體來實現它呢?
一個類中的每個成員都可以用相應的反射包中的一個類的實例對象來表示,通過Class類的方法可以得到這些實例對象;這個“成員”就包括:類的構造函數、成員變量、方法等一些信息。而他們所對應的反射包中的類分別是:Constructor類、Field類、Method類。
這里只要講講動態代理的知識。
二、動態代理
Java動態代理類位于Java.lang.reflect包下,一般主要涉及到以下兩個類:(1). Interface InvocationHandler:該接口中僅定義了一個方法Object:invoke(Object obj,Method method, Object[] args)。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的參數數組。 這個抽象方法在代理類中動態實現。
(2).Proxy:該類即為動態代理類,作用類似于上例中的ProxySubject,其中主要包含以下內容:
Protected Proxy(InvocationHandler h):構造函數,估計用于給內部的h賦值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部接口的數組。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理類的一個實例,返回后的代理類可以當作被代理類使用(可使用被代理類的在Subject接口中聲明過的方法)。實例:
1、定義一個HelloWorld接口
/** * 定義一個HelloWorld接口 * * @author * */ public interface HelloWorld { public void sayHelloWorld(); }
2、類HelloWorldImpl是HelloWorld接口的實現
/** * 類HelloWorldImpl是HelloWorld接口的實現 * * @author * */ public class HelloWorldImpl implements HelloWorld{ public void sayHelloWorld() { System.out.println("HelloWorld!"); } }
3、HelloWorldHandler是 InvocationHandler接口實現
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 實現在方法調用前后向控制臺輸出兩句字符串 * * @author * */ public class HelloWorldHandler implements InvocationHandler{ //要代理的原始對象 private Object obj; public HelloWorldHandler(Object obj) { super(); this.obj = obj; } /** * 在代理實例上處理方法調用并返回結果 * * @param proxy 代理類 * @param method 被代理的方法 * @param args 該方法的參數數組 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; //調用之前 doBefore(); //調用原始對象的方法 result=method.invoke(obj, args); //調用之后 doAfter(); return result; } private void doBefore(){ System.out.println("before method invoke"); } private void doAfter(){ System.out.println("after method invoke"); } }4、測試類
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class HelloWorldTest { public static void main(String[] args) { HelloWorld helloWorld=new HelloWorldImpl(); InvocationHandler handler=new HelloWorldHandler(helloWorld); //創建動態代理對象 HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance( helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), handler); proxy.sayHelloWorld(); } }運行結果為:
before method invoke
HelloWorld
after method invoke
總結:
一個典型的動態代理創建對象過程可分為以下四個步驟:
1、通過實現InvocationHandler接口創建自己的調用處理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通過為Proxy類指定ClassLoader對象和一組interface創建動態代理類
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通過構造函數創建代理類實例,此時需將調用處理器對象作為參數被傳入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
為了簡化對象創建過程,Proxy類中的newInstance方法封裝了2~4,只需兩步即可完成代理對象的創建。
生成的ProxySubject繼承Proxy類實現Subject接口,實現的Subject的方法實際調用處理器的invoke方法,而invoke方法利用反射調用的是被代理對象的的方法(Object result=method.invoke(proxied,args))
綜合上面所說的,作為一個Dynamic Proxy,它必須滿足以下三個條件:
1、實現了InvocationHandler接口,實現接口中定義的invoke方法;
2、包含接口實現類的實例;
3、通過Proxy.newProxyInstance方法實現Proxy與接口之間的綁定
再來回顧一下定義
Dynamic Proxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,然后該class就宣稱它實現了這些 interface。你當然可以把該class的實例當作這些interface中的任何一個來用。當然啦,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質性的工作,在生成它的實例時你必須提供一個handler,由它接管實際的工作 。
來自: http://blog.csdn.net//u011067360/article/details/25040463