在之前Java代理模式中大致的分析了下代理模式的类型及对每种代理类型简单的举例了下。本文将对JDK动态代理进行详细的分析。读完本文,你将对JDK的动态代理的运行流程,生成的代理类结构以及实现的原理有一个更加深入的认识。
本文将从以下几个方面概述:
目录
一:JDK动态代理简单样例
这里我们还是从一个小例子入手:
//获取(不同国家人)说什么语言的接口
public interface Person {
String getSpeakLanguage();
}
//两个实现类 分别为 说中文 和 说英文
public class PersonA implements Person {
public String getSpeakLanguage() {
return "说中文";
}
}
public class PersonB implements Person {
public String getSpeakLanguage() {
return "说英文";
}
}
/**
* 代理类
*/
public class PersonProxy implements InvocationHandler {
private Object target;
public Object getInstance(Object target){
this.target =target;
Class<?> clazz = target.getClass();
/**
* 三个参数为:目标类加载器,目标类实现的接口 代理类本省
*/
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实际执行方法的地方
Object result = method.invoke(target, args);
return result;
}
}
//测试类
public static void main(String[] args) {
Person instance = (Person) new PersonProxy().getInstance(new PersonA());
//instance实际上已经是生成的代理的对象了,而不是之前的(PersonA)对象了
System.out.println(instance.getClass()); // com.sun.proxy.$Proxy0
System.out.println(instance.getSpeakLanguage());
}
这里需要注意的几点是:
1:JDK代理是基于接口的,可参考Java代理模式。即接口是实现JDK代理的基础。
2:Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this) 第三个参数为代理者本身,本样例中即为 PersonProxy对象。
3:method.invoke(target, args) 执行的时候,target为具体的目标类对象而不是生成的代理类对象。在样例中切记不能写为method.invoke(proxy, args)。即不要写为代理类的方法,否则会造成死循环的问题(这里在下文会分析)。注: target 为目标类对象,即本文中的PersonA 和PersonB对象。proxy为JDK为我们生成的动态代理的对象。
4:在测试类中通过动态代理类生成的对象已经是动态代理类了而不是之前我们自己手动创建的类对象了。
二:JDK动态代理生成的代理类分析
在上文说到通过代理类 生成的类已经不是之前我们手动生成的类对象了。即样例中的instance已经为JDK动态代理新生成的一个代理类了。这里我们手动来生成一个接口的代理类,看看他的内部究竟是什么样的结构。
public static void main(String[] args) throws IOException {
//基于Person接口 生成一个代理类的类名为$Proxy0的类字节码文件
byte[] generateProxyClass = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
//输出为字节码文件
FileOutputStream fos =new FileOutputStream("$Proxy0.class");
fos.write(generateProxyClass);
fos.close();
}
通过以上代码生成的解码码class文件经过反编译为:
import com.sg.spring04.proxy.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//代理类$Proxy0 继承与Proxy,以及实现了接口Person
public final class $Proxy0 extends Proxy implements Person
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) throws {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) throws
{
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).