最近在测试spring事务传播性的时候接触到spring使用的代理方式,其中一种就是JDK动态代理。自己就研究了一下,看看具体的实现流程。
1. 简单案例
接口以及实现类
public interface Service {
void test();
}
public class ServiceImpl implements Service {
@Override
public void test() {
System.out.println("test");
}
}
逻辑代码
public class CompileTest {
public static void main(String[] args) throws IOException {
// 保存生成的代理类的字节码文件 这样idea目录下面可以找到对应的代理类的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 自己手动去生成class文件保存到本地
byte[] bts = ProxyGenerator.generateProxyClass("ServiceProxy", interfaces);
FileOutputStream fos = new FileOutputStream(new File("/data/ServiceProxy.class"));
fos.write(bts);
fos.flush();
fos.close();
System.out.println("生成class文件结束");
// 下面是动态代理的测试用例
Service service = new ServiceImpl();
Class<?>[] interfaces = service.getClass().getInterfaces();
Service proxy = (Service) Proxy.newProxyInstance(service.getClass().getClassLoader(), interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "被代理调用");
// 调用具体实例来执行原先的逻辑,传过来的 proxy 是代理类,用他做参数的话会导致循环调用,栈溢出
method.invoke(service, args);
return proxy;
}
});
System.out.println(proxy.getClass());
proxy.test();
}
}
输出内容如下
生成class文件结束
class com.sun.proxy.$Proxy0
test被代理调用
test
找到对应class文件,拖入idea后可以反编译出java代码,如下:
// 生成的代理类实现了对应的接口,并继承Proxy,由于无法多继承,不能代理类,如果传入类,在下面校验的时候会抛IllegalArgumentException
// 重写了equals、hashCode、toString方法
// 可以看到其中有一些Method变量,在最后的静态代码块中,通过反射获取这些方法
// 并且每个方法都用 InvocationHandler 调用来实现增强
public final class ServiceProxy extends Proxy implements Service {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
// 构造函数接收 InvocationHandler 的对象,也就是我们具体增强的内容 下文会说到
public ServiceProxy(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 test() throws {
try {
// 调用 InvocationHandler 的invoke方法来实现方法的代理增强
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.devil.spring.transaction.jdk.Service").getMethod("test");
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());
}
}
}
PS: 这里有个面试问题,为什么jdk动态代理只能实现接口而不能用实体类。也就是为什么不让ServiceProxy去继承ServiceImpl重写对应的方法。这里因为java是单继承的,由于生成后的代理类已经继承了proxy。
2. 源码解析
本文源码基于jdk1.8
先来看看创建的方法,Proxy.newProxyInstance
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
// 判断是否传入InvocationHandler,如果为空,则抛出空指针异常
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
// ......
// 先生成接口的代理类的字节码文件
Class<?> cl = getProxyClass0(loader, intfs);
// 下面这里,调用构造函数,并传入 InvocationHandler,与上面构造函数那里联系起来了
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// ......
return cons.newInstance(new Object[]{h});
}
调用getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 翻译内容如下:如果接口实现的代理类已经存在,则直接返回缓存中的,否则通过ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
WeakCache.get(K key, P parameter)
public V get(K key, P parameter) {
// ......
// subKeyFactory 也就是上面的 KeyFactory()
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 从缓存中度
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
也就是如果supplier不存在则创建Factory对象,赋值给supplier,调用supplier.get()并返回
WeakCache下的Factory.get方法
public synchronized V get() {
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
return null;
}
V value = null;
try {
// valueFactory 也就是 ProxyClassFactory
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
}
// ......
return value;
}
调用ProxyClassFactory.apply方法
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 所有代理类名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
// 下个代理类唯一值如:$Proxy0
private static final AtomicLong nextUniqueNumber = new AtomicLong();
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 类加载器是否能通过接口名称加载该类
Class<?> interfaceClass = Class.forName(intf.getName(), false, loader);
if (interfaceClass != intf) {
throw new IllegalArgumentException(intf + " is not visible from class loader");
}
// 类是否实现对应接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
}
// 接口是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // 代理类的包名放这里
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// ......省略一段代码,非public接口,使代理类的包名与接口的包名相同
if (proxyPkg == null) {
// public代理接口,使用com.sun.proxy包名
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 选择生成代理类的名称
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理类的二进制文件,这里是重点了,就如同测试用例中的方式一样,生成一个接口的代理类
// boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
// 方法中会判断是否需要将class保存到磁盘
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 加载代理类的字节码文件
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}