要了解JDK的动态代理,我们首先要知道为什么需要动态代理,而不是普通的静态代理
先看一个简单的静态代理
- 被代理的接口
public interface HelloWorld {
void sayHello(String name);
}
- 被代理实现类
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();
}
}
执行测试类,输出:
Before sample proxy----> hello nice world: wangjn After sample proxy---->
可以看到,这是一个很简单的代理模式,我们写一个这样的类也很快。可问题是,如果我们有十几二十个类似HelloWorld这样的业务逻辑需要代理,我们就需要写十几二十个代理类,这是无法避免的且无法忍受的 由此引申出动态代理
动态代理的实现
实现一个动态代理也非常简单
- 动态代理类 实现 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");
}
}
运行结果:
Before invocation----> hello nice world: wangjn <----After invocation
主要实现逻辑在 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的构造方法 参数类型为 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;
}
});
}
// 调用参数为 InvocationHandler h 的构造方法创建实例
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文件长什么样吧..
那我们现在就来看一下 这个动态生成的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());
}
}
}
看了动态生成的class,疑惑瞬间解了一大半
- $Proxy0 实现了HelloWorld接口,且继承了Proxy 类。
- 并且构造函数的参数就是
InvocationHandler h
(我们自己实现的HelloWorldInvocationHandler代理类),跟Proxy中的newProxyInstance方法终于对接上了! - 每个 Method 也都在静态块里进行了初始化..
不过JDK动态代理有致命弱点,因为java不允许多继承,而动态生成的class 却继承了Proxy类! 只能是实现了接口的类才可以被代理
不过好在之后已经有了解决方案.
网友评论