動態代理的使用和實現機制
工作中很久沒有接觸動態代理,之前的學習也有些模糊,導致有些遺忘,這裏記錄下個人對動態代理的理解,如有讀者發現問題多多指正吧。
就java而言對於動態代理的支持多是以接口實現,其實現主要是通過java.lang.reflect.Proxy類,java.lang.reflect.InvocationHandler接口。Proxy類主要用於獲取動態代理對象,InvocationHandler接口用來約束調用者實現。
動態代理運行機制:
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法會返回一個代理對象類的實例。當程序執行時會通過反射機制動態的生成一個代理類,該類實現一個接口裏的方法(也就是說代理類與被代理類有相同的接口),在該代理類裏面有一個InvocationHandler類型的成員變量,也就是調用處理程序,通過調用處理程序來給被代理類增強功能。創建好代理類後就調用類加載器將該類加載到類存,然後再通過反射創建一個該代理類的實例對象。下面是具體實現:
1.代理接口:Moveable.java package com.test; public interface Moveable { void move(); } 2.被代理對象:Tank.java import java.util.Random; public class Tank implements Moveable { public void move() { } 3.為被代理對象產生一個代理類對象,其中是想增加記錄運行時間的功能 package com.test; import java.io.File; import javax.tools.JavaCompiler; public class Proxy { 4.TankProxy.java package com.test; import java.lang.reflect.Method; public class TankProxy { 5.測試程序: package com.test; import java.util.List; import com.extend.Tank2; public class Test { } 執行該程序的結果為: 動態生成的代理類的內容如下: package com.test; } |
小結:動態代理在運行期通過接口動態生成代理類,這為其帶來了一定的靈活性,但這個靈活性卻帶來了兩個問題,第一代理類必須實現一個接口,如果沒實現接口會拋出一個異常。第二性能影響,因為動態代理使用反射的機制實現的,首先反射肯定比直接調用要慢,其次使用反射大量生成類文件可能引起Full GC造成性能影響,因為字節碼文件加載後會存放在JVM運行時區的方法區(或者叫持久代)中,當方法區滿的時候,會引起Full GC,所以當你大量使用動態代理時,可以將持久代設置大一些,減少Full GC次數。
引用前者:殘劍
動態代理的使用和實現機制