在之前的一篇文章中 , 我们简单了解了一下代理模式(JAVA设计模式 - 代理模式) , 本篇我们来学习一下动态代理的实现原理 , 以及源码是怎样的 .
JDK动态代理的主要实现步骤如下 :
1 . 声明一个handler类 , 实现InvovationHandler接口 , 然后重写它的invoke方法 , 在此方法中完成扩展逻辑 . 在生成动态代理类之后 , 原方法的调用就是会执行这个invoke方法
2 . 利用Proxy类的静态方法newProxyInstance创建了一个动态代理实例 , 传入了类加载器,需要实现的接口,方法调用的实际处理者,即第一步的handler类 , 然后查看该方法的源码 , 发现它为我们封装了创建动态代理类的步骤 , 返回了一个代理对象实例
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
Objects.requireNonNull(h);//handler不能为null
final Class>[] intfs = interfaces.clone();//代理类需要实现的接口
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
Class> cl = getProxyClass0(loader, intfs);//通过loader和接口 , 得到代理的class对象 , 同时会把class对象缓存一份 , 在代理对象存活于内存中的这段时间 , 就不再创建新的class实例
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});//创建代理对象的实例 , 并将InvocationHandler传入
} 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);
}
}
经过以上操作 , 就在内存中新建了一个拥有我们扩展行为的代理类
3 . 在动态代理中 , 代理类是在内存中动态生成的 , 所以我们没法查看里面有什么内容 , 所以我们要想办法先把动态代理生成的内容显示出来 , 先看下内部结构如何 . 该操作通过如下工具类完成
package com.xbz.xstudy.shejimoshi.proxy;
import org.springframework.cglib.core.DefaultGeneratorStrategy;
import org.springframework.cglib.proxy.Enhancer;
import sun.misc.ProxyGenerator;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* @title 用来将代理对象输出到文件 , 便于分析
* @author Xingbz
* @createDate 2019-4-23
*/
public interface ProxyClassOutUtil {
static void jdkOut(String className, Class[] classArr, String outPath) {
try {
Files.write(Paths.get(outPath), ProxyGenerator.generateProxyClass(className, classArr));
} catch (Exception e) {
System.err.println("JDK代理对象输出异常 . " + e.getMessage());
}
System.out.println("JDK代理对象输出完成");
}
static void cdlibOut(Enhancer enhancer, String outPath) {
try {
Files.write(Paths.get(outPath), DefaultGeneratorStrategy.INSTANCE.generate(enhancer));
} catch (Exception e) {
System.err.println("CGLIB代理对象输出异常 . " + e.getMessage());
}
System.out.println("CGLIB代理对象输出完成");
}
}
我们在JDK动态代理测试类方法末尾增加一行
package com.xbz.xstudy.shejimoshi.proxy.dynamic.jdk;
import com.xbz.xstudy.shejimoshi.proxy.ProxyClassOutUtil;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface;
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterfaceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @title JDK动态代理测试类
* @author Xingbz
* @createDate 2019-4-23
*/
public class Demo {
public static void main(String[] args){
ActorInterface actor = new ActorInterfaceImpl();
InvocationHandler proxyFactory = new ProxyHandler(actor);
ActorInterface actorProxy = (ActorInterface) Proxy.newProxyInstance(ActorInterface.class.getClassLoader(), new Class[]{ActorInterface.class}, proxyFactory);
actorProxy.show();
//将动态生成的代理对象输出到文件
ProxyClassOutUtil.jdkOut("ActorInterface$Proxy0", ActorInterfaceImpl.class.getInterfaces(),"target\\ActorInterface$Proxy0.class");
}
}
然后我们就可以在target\下发现一个ActorIntreface$Porxy.class , 打开内容如下 :
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ActorInterface$Proxy0 extends Proxy implements ActorInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public ActorInterface$Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void show() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.xbz.xstudy.shejimoshi.proxy.targetObject.ActorInterface").getMethod("show");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到该类继承了Proxy父类且实现了与目标对象相同的接口 , 接下来重点关注下show方法 , 里面有这么一行
super.h.invoke(this, m3, (Object[])null);
所以该方法的最终实现 , 就是调用了super.h(即父类Proxy的h)来处理 , 那么h又是从何而来呢? 再来看一下Proxy中的源码
public class Proxy implements java.io.Serializable {
//...
protected InvocationHandler h;
//...
}
没错 , 就是我们声明的一个类来最终完成的这些操作 . 所以JDK动态代理大致的步骤如下