上一篇我們實(shí)現(xiàn)了對(duì)所選擇的接口的所有方法實(shí)現(xiàn)代理,但是代理邏輯卻已經(jīng)被寫死了,自然不是很合適,這一篇我們便來(lái)解決這個(gè)問(wèn)題灵奖,實(shí)現(xiàn)自定義代理邏輯的動(dòng)態(tài)代理嚼沿,實(shí)現(xiàn)之后我們的動(dòng)態(tài)代理就已經(jīng)很接近 JDK 自帶的代理了。
- 要實(shí)現(xiàn)自定義代理邏輯瓷患,相信大家首先能想到的應(yīng)該是定義一個(gè)接口 InvocationHandler 骡尽,我們所自定義的代理邏輯應(yīng)該是實(shí)現(xiàn)了這個(gè)接口的邏輯類。
InvocationHandler 代碼:package dynamicProxy; import java.lang.reflect.Method; public interface InvocationHandler { void invoke(Object o ,Method method) ; }
- 定義一種代理邏輯擅编,把目標(biāo)對(duì)象跟方法傳進(jìn)來(lái)攀细。這里還是采用之前的代理邏輯即時(shí)間代理。
TimeHandler 代碼:
這里的 target 為被代理對(duì)象沙咏,package dynamicProxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { public TimeHandler(Object target) { this.target = target; } private Object target ; @Override public void invoke(Object o, Method method) { long startTime = System.currentTimeMillis() ; try { method.invoke(target, new Object[]{}) ; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } long endTime = System.currentTimeMillis() ; System.out.println("time : " + (endTime - startTime)) ; } }
method.invoke(target, new Object[]{}) ;
中的 Object 數(shù)組是執(zhí)行該方法的參數(shù)辨图,這里為了簡(jiǎn)便操作先定義一個(gè)空數(shù)組。 - 接下來(lái)我們理所應(yīng)當(dāng)想到的就是修改生成代理類的工具肢藐,把代理邏輯也傳進(jìn)去故河。這里需要修改的地方有幾處:
- 修改生成代理類的類,添加 newInstance 方法的參數(shù) InvocationHandler:
public static Object newInstance(Class inface,InvocationHandler h)
- 修改代理類的生成代碼 str,構(gòu)造方法不再是所給定的代理類,而是 InvocationHandler
"public class TankTimeProxy implements "+ inface.getName() + "{\n" + " public TankTimeProxy(InvocationHandler h) {\n" + " this.handler = h;\n" + " }\n" + "\n" + " private InvocationHandler handler ;\n" + "\n" +
- 方法字符串中吆豹,原本是執(zhí)行方法的 invoke 方法(
md.invoke(this, new Object[]{}) ;
),現(xiàn)在改為執(zhí)行 handler 的 invoke 方法
" handler.invoke(this, md) ; \n" +
- 修改構(gòu)造器參數(shù):
Constructor constructor = c.getConstructor(InvocationHandler.class) ; Object m = constructor.newInstance(handler);
實(shí)際上到了這里鱼的,我們要實(shí)現(xiàn)的動(dòng)態(tài)代理就已經(jīng)完成了,可以完成對(duì)任意接口的所有方法實(shí)現(xiàn)我們自定義的代理邏輯痘煤。
這里再給出 Client 代碼 :
Tank tank = new Tank() ;
Moveable tankTimeProxy = (Moveable)Proxy.newInstance(Moveable.class, new TimeHandler(tank)) ;
tankTimeProxy.move();
代碼結(jié)果:
最后有幾點(diǎn)需要說(shuō)明:
- 為什么代理類的構(gòu)造方法要改為 InvocationHandler?
我們已經(jīng)知道凑阶,要實(shí)現(xiàn)代理肯定要有被代理對(duì)象,而我們?cè)诙x代理邏輯類的時(shí)候衷快,已經(jīng)把被代理對(duì)象作為構(gòu)造方法的參數(shù)傳進(jìn)來(lái)了宙橱,所以代理類的構(gòu)造方法定義為 InvocationHandler ,既包括了代理邏輯蘸拔,也包括了被代理對(duì)象师郑。 - 代理字符串中的 handler.invoke(this, md) 其中的 this 怎么理解?
this 關(guān)鍵字相信大家都有所了解调窍,就是當(dāng)前對(duì)象宝冕。那么在代理類字符串中,this 自然代表了代理對(duì)象邓萨。而我們代理邏輯中地梨,這個(gè)對(duì)象暫時(shí)沒有用到,但不代表以后我們不會(huì)用到缔恳。在 JDK 中宝剖,這個(gè)代理類的名字叫 $Proxy1 有興趣的可以去看看。