Proxy 是設計模式中的一種。當須要在已存在的 class 上添加或修改功能時,能夠經過建立 proxy object 來實現java
一般 proxy object 和被代理對象擁有相同的方法,而且擁有被代理對象的引用,能夠調用其方法程序員
代理模式應用場景包括面試
代理有兩種實現方式sql
對於重複性工做,如打印日誌,靜態代理須要爲每一個 class 都建立 proxy class,過程繁瑣和低效,而動態代理經過使用反射在運行時生成 bytecode 的方式來實現,更加方便和強大設計模式
由於 JDK 自帶的 Dynamic proxy 只可以代理 interfaces,所以被代理對象須要實現一個或多個接口。架構
先來看一些概念:併發
proxy interface
proxy class 實現的接口proxy class
運行時建立的代理 class,並實現一個或多個 proxy interfaceproxy instance
proxy class 的實例InvocationHandler
每一個 proxy instance 都有一個關聯的 invocation handler,當調用 proxy 對象的方法時,會統一封裝,並轉發到 invoke()
方法InvocationHandler 接口的定義以下分佈式
package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
只定義了一個方法 invoke()
,參數含義以下ide
Object proxy
生成的代理對象Method method
調用的方法,類型爲 java.lang.reflect.Method
Object[] args
調用方法的參數,array of objects簡單來講就是,調用 proxy object 上的方法,最終都會轉換成對關聯 InvocationHandler
的 invoke()
方法的調用高併發
能夠使用 java.lang.reflect.Proxy
的靜態方法 newProxyInstance
來建立 Proxy object
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... }
參數說明
使用動態代理打印方法的執行耗時
定義代理接口
public interface Foo { String doSomething(); }
實現接口
public class FooImpl implements Foo { @Override public String doSomething() { return "finished"; } }
定義 InvocationHandler,target 爲被代理對象的引用,在方法執行完後打印耗時
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimingInvocationHandler implements InvocationHandler { private Object target; public TimingInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.nanoTime(); Object result = method.invoke(target, args); long elapsed = System.nanoTime() - start; System.out.println(String.format("Executing %s finished in %d ns", method.getName(), elapsed)); return result; } }
測試
import org.junit.Test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxyTest { @Test public void test() { ClassLoader cl = DynamicProxyTest.class.getClassLoader(); Class[] interfaces = new Class[]{Foo.class}; FooImpl fooImpl = new FooImpl(); InvocationHandler timingInvocationHandler = new TimingInvocationHandler(fooImpl); Foo foo = (Foo) Proxy.newProxyInstance(cl, interfaces, timingInvocationHandler); foo.doSomething(); } }
執行完會打印相似
Executing doSomething finished in 23148 ns
生成 proxy class 的一些屬性和細節
分享免費學習資料
針對於Java程序員,我這邊準備免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)
爲何某些人會一直比你優秀,是由於他自己就很優秀還一直在持續努力變得更優秀,而你是否是還在知足於現狀心裏在竊喜!但願讀到這的您能點個小贊和關注下我,之後還會更新技術乾貨,謝謝您的支持!
資料領取方式:加入Java技術交流羣963944895
,點擊加入羣聊,私信管理員便可免費領取