初步探究jdk动态代理
1.先看代码实现
package club.jiajiajia.test.staticproxy;
public interface BuyHouse {
void buyHosue();//买房子
}
package club.jiajiajia.test.staticproxy;
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("买房子");
}
}
package club.jiajiajia.test.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房前准备");
Object result = method.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
public static void main(String[] args) {
try {
//生成$Proxy0的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//必须在main函数中才能生成
//获取动态代理类字节码文件
Class proxyClazz = Proxy.getProxyClass(BuyHouse.class.getClassLoader(),BuyHouse.class);
//获得代理类的构造函数
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
//通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
BuyHouse proxyBuyHouse = (BuyHouse) constructor.newInstance(new DynamicProxyHandler(new BuyHouseImpl()));
//通过代理对象调用目标方法
proxyBuyHouse.buyHosue();
System.out.println();
BuyHouse buyHouse = new BuyHouseImpl();//未被代理对象
System.out.println("proxyBuyHouse 对象是否是 Proxy 的实例:"+(proxyBuyHouse instanceof Proxy));
System.out.println("buyHouse 对象是否是 BuyHouse 的实例:"+(buyHouse instanceof BuyHouse));
System.out.println("proxyBuyHouse 对象是否是 BuyHouse 的实例:"+(proxyBuyHouse instanceof BuyHouse));
System.out.println("proxyBuyHouse 对象是否是 BuyHouseImpl 的实例:"+(proxyBuyHouse instanceof BuyHouseImpl));
System.out.println("代理对象的全类名:"+proxyBuyHouse.getClass().getName());
System.out.println("代理类的父类:"+proxyBuyHouse.getClass().getSuperclass().getName());
Class<?>[] c=proxyBuyHouse.getClass().getInterfaces();
System.out.println();
for (Class<?> inte : c) {//打印
System.out.println("代理类实现接口:"+inte);
}
} catch (Exception e) {
e.printStackTrace();
}
}
运行打印:
买房前准备
买房子
买房后装修
proxyBuyHouse 对象是否是 Proxy 的实例:true
buyHouse 对象是否是 BuyHouse 的实例:true
proxyBuyHouse 对象是否是 BuyHouse 的实例:true
proxyBuyHouse 对象是否是 BuyHouseImpl 的实例:false
代理对象的全类名:com.sun.proxy.$Proxy0
代理类的父类:java.lang.reflect.Proxy
代理类实现接口:interface club.jiajiajia.test.staticproxy.BuyHouse
2.运行原理
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
也就是说我们用的代理类的对象已经不是BuyHouseImpl的类模板所生成的对象了,而是jdk在运行期间由JVM根据反射等机制动态生成代理类的字节码文件 类似 $Proxy0.class,代理类的对象就是以这个.class文件为类模板创建的对象,but我们看不到这个.class文件,但是java提供了一个方法可以把这个class文件保存在本地。
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//必须在main函数中才能生成

然后用反编译工具反编译这个文件如下:
package com.sun.proxy;
import club.jiajiajia.test.staticproxy.BuyHouse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements BuyHouse {
private static Method m1;
private static Method m2;
private static Method m0;
private static Method m3;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString() {
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode() {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void buyHosue() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("club.jiajiajia.test.staticproxy.BuyHouse").getMethod("buyHosue", new Class[0]);
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
观察这个$Proxy0.java类会发现有如下几点:
1.这个类继承了Proxy类
2.实现了我们所定义的BuyHouse接口
3.它的构造方法中需要传入InvocationHandler实例
4.它重写了buyHosue方法以及其他方法
5.用反射获取了目标方法的引用(用于反射调用)
那么由这几个特点我绘制了下面这个图:

代理对象的创建
从上图中可以发现 Proxy 类中有 InvocationHandler 属性,(注意:这个属性与 我们定义的DynamicProxyHandler类有着直接的关系,)
Class proxyClazz = Proxy.getProxyClass(BuyHouse.class.getClassLoader(),BuyHouse.class);
这一行代码是在帮我们创建代理类的类文件
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
这个是获得该类的构造方法,并由该方法创建代理对象
BuyHouse proxyBuyHouse = (BuyHouse) constructor.newInstance(new DynamicProxyHandler(new BuyHouseImpl()));
这一步才是真正的根据代理类的构造方法创建代理对象,会发现参数我们传入了DynamicProxyHandler的实例
在创建代理类的过程中 $Proxy0 的构造方法有调用了父类的构造方法 并传入DynamicProxyHandler的实例,并且可以看到,
父类的InvocationHandler属性引用了该对象.....其他的不重要.....至此,代理对象创建完成
代理方法的调用
当在调用BuyHouse的buyHosue()方法的时候,实际是调用了代理对象重写了BuyHouse接口的buyHosue()方法即:
public final void buyHosue() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
此方法紧接着调用了父类的InvocationHandler属性(即 h对象)的invoke方法(即我们定义的DynamicProxyHandler类的invoke方法,),在其方法内又通过反射调用的我们在创建DynamicProxyHandler对象时传入的目标对象buyHosue()方法
所以我们可以在其调用前后做一些其他的事情。
到此方法调用结束。
这就是我理解的jdk动态代理
对于代理类时如何生成的,这还得继续研究。
