Java動(dòng)態(tài)代理機(jī)制的出現(xiàn),使得 Java 開(kāi)發(fā)人員不用手工編寫代理類,只要簡(jiǎn)單地指定一組接口及委托類對(duì)象,便能動(dòng)態(tài)地獲得代理類。
我們提供的服務(wù)有:網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、平陰ssl等。為千余家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的平陰網(wǎng)站制作公司
代理類會(huì)負(fù)責(zé)將所有的方法調(diào)用分派到委托對(duì)象上反射執(zhí)行,在分派執(zhí)行的過(guò)程中,開(kāi)發(fā)人員還可以按需調(diào)整委托類對(duì)象及其功能,這是一套非常靈活有彈性的代理框架。下面我們開(kāi)始動(dòng)態(tài)代理的學(xué)習(xí)。
動(dòng)態(tài)代理的簡(jiǎn)要說(shuō)明
在java的動(dòng)態(tài)代理機(jī)制中,有兩個(gè)重要的類或接口,一個(gè)是 InvocationHandler(Interface)、另一個(gè)則是 Proxy(Class)。
一、 InvocationHandler(interface)的描述:
InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
每一個(gè)動(dòng)態(tài)代理類都必須要實(shí)現(xiàn)InvocationHandler這個(gè)接口,并且每個(gè)代理類的實(shí)例都關(guān)聯(lián)到了一個(gè)handler,當(dāng)我們通過(guò)代理對(duì)象調(diào)用 一個(gè)方法的時(shí)候,這個(gè)方法的調(diào)用就會(huì)被轉(zhuǎn)發(fā)為由InvocationHandler這個(gè)接口的 invoke 方法來(lái)進(jìn)行調(diào)用。我們來(lái)看看InvocationHandler這個(gè)接口的唯一一個(gè)方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
這個(gè)方法接收三個(gè)參數(shù)和返回一個(gè)Object類型,它們分別代表的意思如下:
proxy: 指代我們所代理的那個(gè)真實(shí)對(duì)象
method: 指代的是我們所要調(diào)用真實(shí)對(duì)象的方法的Method對(duì)象
args: 指代的是調(diào)用真實(shí)對(duì)象某個(gè)方法時(shí)接受的參數(shù)
返回的Object是指真實(shí)對(duì)象方法的返回類型,以上會(huì)在接下來(lái)的例子中加以深入理解。
the value to return from the method invocation on the proxy instance.
二、 Proxy(Class)的描述:
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.
Proxy這個(gè)類的作用就是用來(lái)動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象。我們經(jīng)常使用的是newProxyInstance這個(gè)方法:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參數(shù)的理解:
// 一個(gè)ClassLoader對(duì)象,定義了由哪個(gè)ClassLoader對(duì)象來(lái)對(duì)生成的代理對(duì)象進(jìn)行加載 loader - the class loader to define the proxy class // 一個(gè)Interface對(duì)象的數(shù)組,表示的是我將要給我需要代理的對(duì)象提供一組什么接口 interfaces - the list of interfaces for the proxy class to implement // 一個(gè)InvocationHandler對(duì)象,表示的是當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象在調(diào)用方法的時(shí)候,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上 h - the invocation handler to dispatch method invocations to
返回結(jié)果的理解: 一個(gè)代理對(duì)象的實(shí)例
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
簡(jiǎn)單的Java代理
我們創(chuàng)建一個(gè)Java項(xiàng)目用于對(duì)動(dòng)態(tài)代理的測(cè)試與理解,項(xiàng)目結(jié)構(gòu)如下:
一、 先定義一個(gè)接口Interface,添加兩個(gè)方法。
package com.huhx.proxy; public interface Interface { void getMyName(); String getNameById(String id); }
二、 定義一個(gè)真實(shí)的實(shí)現(xiàn)上述接口的類,RealObject:
package com.huhx.proxy; public class RealObject implements Interface { @Override public void getMyName() { System.out.println("my name is huhx"); } @Override public String getNameById(String id) { System.out.println("argument id: " + id); return "huhx"; } }
三、 定義一個(gè)代理對(duì)象,也實(shí)現(xiàn)了上述的Interface接口:
package com.huhx.proxy; public class SimpleProxy implements Interface { private Interface proxied; public SimpleProxy(Interface proxied) { this.proxied = proxied; } @Override public void getMyName() { System.out.println("proxy getmyname"); proxied.getMyName(); } @Override public String getNameById(String id) { System.out.println("proxy getnamebyid"); return proxied.getNameById(id); } }
四、 SimpleMain在Main方法中,測(cè)試上述的結(jié)果:
package com.huhx.proxy; public class SimpleMain { private static void consume(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) { consume(new RealObject()); System.out.println("========================================================"); consume(new SimpleProxy(new RealObject())); } }
五、 運(yùn)行的結(jié)果如下:
my name is huhx argument id: 1 name: huhx ======================================================== proxy getmyname my name is huhx proxy getnamebyid argument id: 1 name: huhx
Java的動(dòng)態(tài)代理
完成了上述簡(jiǎn)單的Java代理,現(xiàn)在我們開(kāi)始學(xué)習(xí)Java的動(dòng)態(tài)代理,它比代理的思想更向前一步,因?yàn)樗梢詣?dòng)態(tài)地創(chuàng)建代理并動(dòng)態(tài)的處理對(duì)所代理方法的調(diào)用。在動(dòng)態(tài)代理上所做的所有調(diào)用都會(huì)被重定向到單一的調(diào)用處理器上,它的工作是揭示調(diào)用的類型并確定相應(yīng)的對(duì)策。下面我們通過(guò)案例來(lái)加深Java動(dòng)態(tài)代理的理解:
一、 創(chuàng)建一個(gè)繼承了InvocationHandler的處理器:DynamicProxyHandler
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Arrays; public class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { System.out.println("dynamic proxy handler constuctor: " + proxied.getClass()); this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("dynamic proxy name: " + proxy.getClass()); System.out.println("method: " + method.getName()); System.out.println("args: " + Arrays.toString(args)); Object invokeObject = method.invoke(proxied, args); if (invokeObject != null) { System.out.println("invoke object: " + invokeObject.getClass()); } else { System.out.println("invoke object is null"); } return invokeObject; } }
二、 我們寫一個(gè)測(cè)試的Main方法,DynamicProxyMain:
package com.huhx.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.huhx.proxy.Interface; import com.huhx.proxy.RealObject; public class DynamicProxyMain { public static void consumer(Interface iface) { iface.getMyName(); String name = iface.getNameById("1"); System.out.println("name: " + name); } public static void main(String[] args) throws Exception, SecurityException, Throwable { RealObject realObject = new RealObject(); consumer(realObject); System.out.println("=============================="); // 動(dòng)態(tài)代理 ClassLoader classLoader = Interface.class.getClassLoader(); Class>[] interfaces = new Class[] { Interface.class }; InvocationHandler handler = new DynamicProxyHandler(realObject); Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler); System.out.println("in dynamicproxyMain proxy: " + proxy.getClass()); consumer(proxy); } }
三、 運(yùn)行結(jié)果如下:
my name is huhx argument id: 1 name: huhx ============================== dynamic proxy handler constuctor: class com.huhx.proxy.RealObject in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0 dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null dynamic proxy name: class com.sun.proxy.$Proxy0 method: getNameById args: [1] argument id: 1 invoke object: class java.lang.String name: huhx
從以上輸出結(jié)果,我們可以得出以下結(jié)論:
與代理對(duì)象相關(guān)聯(lián)的InvocationHandler,只有在代理對(duì)象調(diào)用方法時(shí),才會(huì)執(zhí)行它的invoke方法
invoke的三個(gè)參數(shù)的理解:Object proxy是代理的對(duì)象, Method method是真實(shí)對(duì)象中調(diào)用方法的Method類, Object[] args是真實(shí)對(duì)象中調(diào)用方法的參數(shù)
Java動(dòng)態(tài)代理的原理
一、 動(dòng)態(tài)代理的關(guān)鍵代碼就是Proxy.newProxyInstance(classLoader, interfaces, handler),我們跟進(jìn)源代碼看看:
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // handler不能為空 if (h == null) { throw new NullPointerException(); } final Class>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ // 通過(guò)loader和接口,得到代理的Class對(duì)象 Class> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction
二、 我們看一下newInstance方法的源代碼:
private static Object newInstance(Constructor> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString()); } } }
三、 當(dāng)我們通過(guò)代理對(duì)象調(diào)用 一個(gè)方法的時(shí)候,這個(gè)方法的調(diào)用就會(huì)被轉(zhuǎn)發(fā)為由InvocationHandler這個(gè)接口的 invoke 方法來(lái)進(jìn)行調(diào)用。
體現(xiàn)這句話的代碼,我在源碼中沒(méi)有找到,于是我在測(cè)試類的main方法中加入以下代碼:
if (proxy instanceof Proxy) { InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy); invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null); System.out.println("--------------------------------------"); }
這段代碼的輸出結(jié)果如下,與上述中調(diào)用代理對(duì)象中的getMyName方法輸出是一樣的,不知道Jvm底層是否是這樣判斷的:
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject dynamic proxy name: class com.sun.proxy.$Proxy0 method: getMyName args: null my name is huhx invoke object is null --------------------------------------
以上就是Java動(dòng)態(tài)代理的原理的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!