Proxy 是設計模式中的一種。當須要在已存在的 class 上添加或修改功能時,能夠經過建立 proxy object 來實現java
一般 proxy object 和被代理對象擁有相同的方法,而且擁有被代理對象的引用,能夠調用其方法程序員
代理模式應用場景包括面試
代理有兩種實現方式sql
對於重複性工做,如打印日誌,靜態代理須要爲每一個 class 都建立 proxy class,過程繁瑣和低效,而動態代理經過使用反射在運行時生成 bytecode 的方式來實現,更加方便和強大設計模式
由於 JDK 自帶的 Dynamic proxy 只可以代理 interfaces,所以被代理對象須要實現一個或多個接口。bash
先來看一些概念:架構
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()
,參數含義以下分佈式
Object proxy
生成的代理對象Method method
調用的方法,類型爲 java.lang.reflect.Method
Object[] args
調用方法的參數,array of objects簡單來講就是,調用 proxy object 上的方法,最終都會轉換成對關聯InvocationHandler
的invoke()
方法的調用ide
能夠使用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
,點擊加入羣聊,私信管理員便可免費領取