被代理类接口:
package reflect;
interface TestInterface{
void print();
}
被代理类实现:
package reflect;
class Test implements TestInterface{
public void print() {
System.out.println("I am print");
}
}
InvocationHandler实现类,执行特定被代理类方法的额外操作
class TestProxy implements InvocationHandler {
private Object test;
// 生成代理类
public Object createInstance(Object test) {
this.test = test;
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), test.getClass().getInterfaces(), this);
}
// InvocationHandler的invoke方法的具体实现
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
// 调用被代理类的方法。
// method是指定调用的被代理类的方法,该方法可以是接口类的方法,也可以是被代理类的方法
// this.test是被代理类的实例
Object obj = method.invoke(this.test, args);
System.out.println("after");
return obj;
}
}
测试用例:
public class ProxyTest {
public static void main(String[] args) {
TestProxy testProxy = new TestProxy();
TestInterface test = (TestInterface) testProxy.createInstance(new Test());
test.print();
}
}
jdk动态代理得核心是:
InvocationHandler的实现类TestProxy中调用Proxy.newProxyInstance生成代理类字节码、使用被代理类的类加载器加载代理类字节码、生成代理类实例
下面是生成的代理类字节码
(在java命令中增加-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true参数可将字节码保存到磁盘上)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package general;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements TestInterface {
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 print() 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)).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("general.TestInterface").getMethod("print", new Class[0]);
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());
}
}
}
可以看到,生成的代理类继承了java.lang.reflect.Proxy以及实现了被代理类的TestInterface接口。
结合测试用例来看:
public class ProxyTest {
public static void main(String[] args) {
TestProxy testProxy = new TestProxy();
TestInterface test = (TestInterface) testProxy.createInstance(new Test());
test.print();
}
}
第一行
TestProxy testProxy = new TestProxy();
创建InvocationHandler的实例
第二行
TestInterface test = (TestInterface) testProxy.createInstance(new Test());
InvocationHandler生成代理类对象实例,并赋值给被代理类的接口TestInterface(多态,向上转型)
第三行
test.print();
调用代理类的print方法:
public final void print() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
在代理类的print方法中,回调了InvocationHandler实现类TestProxy的invoke方法。这里m3是被代理类中的print方法的Method实例,在代理类的静态代码块中初始化(类加载阶段初始化):
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("general.TestInterface").getMethod("print", new Class[0]);
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());
}
}
在TestProxy类的invoke方法中,通过
Object obj = method.invoke(this.test, args);
这一行通过反射调用被代理类的print方法,在这一行断点可以看到如下信息
这就是jdk动态代理的执行流程。
拓展:
- jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口
- 另一种将代理类字节码写入磁盘的方式如下(直接调用代理类字节码生成接口,并写入磁盘上,这和之前介绍的方式是一样的原理):
public static void writeProxyClassToHardDisk(String path) {
// 获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserServiceImpl.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}