参考
1、对 JDK 动态代理 使用、源码级解释
https://www.cnblogs.com/CodeBear/p/10245442.html
2、对生成JDK 动态代理代理的类的核心类 ProxyGenerator 进行了介绍
https://www.cnblogs.com/liuyun1995/p/8144706.html
概述
- JDK 动态代理只能代理实现了接口的类,如果一个类没有继承任何的接口,那么就不能代理该类。原因是我们动态生成的所有代理类都必须继承Proxy这个类,Java的单继承特性导致。
- 重写 java.lang.reflect.InvocationHandler#invoke方法的时候, 使用被代理类执行目标方法, 不要使用代理类, 否则会出现循环调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
Object result = method.invoke(target, args);
return result;
}
1、使用方式
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取被代理接口实例对象
*
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>");
Object result = method.invoke(target, args);
return result;
}
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
OrderServiceImpl orderService = new OrderServiceImpl();
OrderService proxy = new JDKDynamicProxy(orderService).getProxy();
proxy.test1("xiaoming");
proxy.test2();
}
2、原理介绍
2.1、JDK 动态代理生成的代理类对象获取方式
-
调用类 ProxyGenerator的 generateProxyClass() 方法可以生成 JDK动态代理类的代理类字节码 sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[], int)
-
执行JDK动态代理程序时, 设置变量保存生成的代理类的字节码 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
public final class $Proxy0 extends Proxy implements OrderService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
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});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void test1(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 void test2() throws {
try {
super.h.invoke(this, m4, (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.wl.springbootdemo.demo.dynamic.jdk.OrderService").getMethod("test1", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("com.wl.springbootdemo.demo.dynamic.jdk.OrderService").getMethod("test2");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
2.2、动态生成类的方式
正常方式生成一个类的方式:
- 拼接代理类的代码
- 输出.java文件
- 编译.java文件成.class文件
- 装载.class文件
- 创建并返回代理类对象
JDK 动态代理生成代理类的方式: JDK动态代理就是通过按照Class文件语法,程序来动态编写Class文件
- 拼接代理类的.class文件
- 装载.class文件
- 创建并返回代理类对象
2.3、源码分析生成代理的过程
JDK 动态代理获取代理类过程 java.lang.reflect.Proxy#newProxyInstance java.lang.reflect.Proxy#getProxyClass0 java.lang.reflect.WeakCache#get java.lang.reflect.WeakCache.Factory#get java.util.function.BiFunction#apply #java.lang.reflect.Proxy.ProxyClassFactory#apply sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[], int)
2.4、ProxyGenerator 的使用方式
JDK 动态代理代理生成代理类的核心类 ProxyGenerator, 方法 sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class<?>[]) 通过程序来动态生成Class文件的 通过反编译 ProxyGenerator 类生成的代理类的字节码,可以看到代理类原文件,了解代理的具体执行原理
public class ProxyUtils {
/*
* 将根据类信息 动态生成的二进制字节码保存到硬盘中,
* 默认的是clazz目录下
* params :clazz 需要生成动态代理类的类
* proxyName : 为动态生成的代理类的名称
*/
public static void generateClassFile(Class clazz, String proxyName) {
//根据类信息和提供的代理类名称,生成字节码
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
// String paths = clazz.getResource(".").getPath();
// System.out.println(paths);
FileOutputStream out = null;
try {
//保留到硬盘中
out = new FileOutputStream("/Users/chenwanli/work/keep/spring-boot-demo/spring-boot-test/src/main/java/com/wl/springbootdemo/demo/dynamic/" + proxyName + ".class");
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ProxyUtils.generateClassFile(User.class, "UserProxy");
}
}