要了解JDK的動態(tài)代理,我們首先要知道為什么需要動態(tài)代理,而不是普通的靜態(tài)代理
先看一個簡單的靜態(tài)代理
- 被代理的接口
public interface HelloWorld {
void sayHello(String name);
}
- 被代理實現(xiàn)類
public class HelloWorldImpl implements HelloWorld {
public void sayHello(String name) {
System.out.println("hello nice world: " + name);
}
}
- 代理類 & 測試類
**
* @author wangjn
* @description 普通代理
* @date Created on 2017/12/26.
*/
public class HelloWorldProxy {
private HelloWorld helloWorld;
HelloWorldProxy (HelloWorld helloWorld) {
this.helloWorld = helloWorld;
}
void sayHello() {
System.out.println("Before sample proxy---->");
helloWorld.sayHello("wangjn");
System.out.println("After sample proxy---->");
}
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorldImpl();
HelloWorldProxy proxy = new HelloWorldProxy(helloWorld);
proxy.sayHello();
}
}
執(zhí)行測試類,輸出:
Before sample proxy----> hello nice world: wangjn After sample proxy---->
可以看到,這是一個很簡單的代理模式,我們寫一個這樣的類也很快。可問題是,如果我們有十幾二十個類似HelloWorld這樣的業(yè)務(wù)邏輯需要代理,我們就需要寫十幾二十個代理類,這是無法避免的且無法忍受的 由此引申出動態(tài)代理
動態(tài)代理的實現(xiàn)
實現(xiàn)一個動態(tài)代理也非常簡單
- 動態(tài)代理類 實現(xiàn) InvocationHandler 接口
public class HelloWorldInvocationHandler implements InvocationHandler{
private Object target;
public HelloWorldInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invocation---->");
Object retVal = method.invoke(target, args);
System.out.println("<----After invocation");
return retVal;
}
}
- 測試類
public class JDKDynamicProxyTest {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
HelloWorldInvocationHandler handler = new HelloWorldInvocationHandler(new HelloWorldImpl());
HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(
JDKDynamicProxyTest.class.getClassLoader(),
new Class[]{HelloWorld.class},
handler);
proxy.sayHello("wangjn");
}
}
運行結(jié)果:
Before invocation----> hello nice world: wangjn <----After invocation
主要實現(xiàn)邏輯在 Proxy.newProxyInstance中
- Proxy.newProxyInstance 方法源碼
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
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.
* 生成Class 文件的重要代碼,這里不深究是如何生成的
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 獲取生成的class的構(gòu)造方法 參數(shù)類型為 InvocationHandler.class
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 調(diào)用參數(shù)為 InvocationHandler h 的構(gòu)造方法創(chuàng)建實例
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
看到這里,我們肯定想要看一下 Class<?> cl = getProxyClass0(loader, intfs)
生成的class文件長什么樣吧..
那我們現(xiàn)在就來看一下 這個動態(tài)生成的class長什么樣
- $Proxy0 反編譯查看
public final class $Proxy0 extends Proxy implements HelloWorld {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayHello(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("com.taromilkbread.bird.HelloWorld").getMethod("sayHello", new Class[]{Class.forName("java.lang.String")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
看了動態(tài)生成的class,疑惑瞬間解了一大半
- $Proxy0 實現(xiàn)了HelloWorld接口,且繼承了Proxy 類。
- 并且構(gòu)造函數(shù)的參數(shù)就是
InvocationHandler h
(我們自己實現(xiàn)的HelloWorldInvocationHandler代理類),跟Proxy中的newProxyInstance方法終于對接上了! - 每個 Method 也都在靜態(tài)塊里進行了初始化..
不過JDK動態(tài)代理有致命弱點,因為java不允許多繼承,而動態(tài)生成的class 卻繼承了Proxy類! 只能是實現(xiàn)了接口的類才可以被代理
不過好在之后已經(jīng)有了解決方案.