普通测试场景
- 业务场景
保存订单信息 - 分层模型
IOrderService -> OrderServiceImpl - 业务代码
public class OrderServiceImpl implements IOrderService {
// spring 会自己注入,这里手动注入
private IOrderDao iOrderDao;
@Override
public int saveOrder(Order order) {
iOrderDao = new OrderDaoImpl();
// 暂时不连接数据库
return 1;
}
}
- 应用层代码
public class Test {
public static void main(String[] args) throws Throwable {
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 数据准备
Order order = new Order();
// 使用动态代理存数据
orderServiceDynamicProxy.saveOrder(order);
}
}
- 自定义的代理代码
实现 InvocationHandler 即可成为动态代理类, 为什么? 需要分析源码
public class OrderServiceDynamicProxy implements InvocationHandler {
// 被代理的对象, 抽象成Object类, 甚至可以不是接口,提高了最大的灵活性
private Object target;
/**
* 核心方法 -- 动态生成被代理类
* @return JVM生成的 $proxy0 文件
*/
public Object bind(){
// 获取代理类的class文件
Class cls = target.getClass();
ClassLoader classLoader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces();
return Proxy.newProxyInstance(classLoader, interfaces,this);
}
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
/**
* 核心方法 -- 需要debug确定该方法的作用
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target, args);
afterMethod();
return object;
}
private void beforeMethod(Object obj){}
private void afterMethod(){}
}
1 jdk源码分析 – debug
-
返回值起源 – 确定返回值
return Proxy.newProxyInstance(classLoader, interfaces,this)
Proxy.newProxyInstance 返回的是 $Proxy0对象
-
返回值追踪 – 定位类
Proxy类拥有创造前缀为$Proxy 的工厂内部类(jdk1.8)确定返回值来源类: java.lang.reflect.Proxy.ProxyClassFactory
-
返回值追踪 – 定位语句
639行出现了一个字节数组,为proxyClassFile,几乎能断定这是动态生成的 $proxy0 字节码文件
-
使用idea工具提取该文件
FileOutputStream fos = new FileOutputStream("D:\\b.class"); fos.write(proxyClassFile);
2 生成的 $proxy0 源码
public final class $Proxy0 extends Proxy implements IOrderService {
private static Method m3;
/**
* 构造方法传入InvocationHandler的实现类
* todo 传入InvocationHandler 的实现类 OrderServiceDynamicProxy
*
* @param var1 OrderServiceDynamicProxy
*/
public $Proxy0(InvocationHandler var1) {
super(var1);
}
/**
*
* 程序调用的是这个方法,而真正执行的是 OrderServiceDynamicProxy 的 saveOrder 方法
* todo 动态生成的 saveOrder() 方法实际调用的是 OrderServiceDynamicProxy 的invoke方法
* todo invoke 方法是约定而成的模板方法
*
* @param var1 在静态代码块中获得的参数列表
*
*/
public final int saveOrder(Order methodVar) throws Throwable { // 参数列表的数量和类型也是从class文件中获取的
// protected InvocationHandler h;
// todo h 是父类Proxy类的成员变量,也就是构造时传入的 OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{methodVar});
}
/**
* todo 静态代码块先执行
*/
static {
try {
m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {
var2.printStackTrace();
}
}
}
3 $proxy0 源码分析
静态代码块通过反射获取调用者的class文件信息
/**
* todo 静态代码块先执行
*/
static {
try {
m3 = Class.forName("com.structural.proxy.IOrderService").getMethod("saveOrder", Class.forName("com.structural.proxy.Order"));
}catch (Exception var2) {
var2.printStackTrace();
}
}
突破口1 —— $proxy0 的成员方法是由应用层决定
自定义的bind方法中存在以下逻辑,可以确定 $proxy0 内的方法不需要事先知道,
在应用层调用的时候传入对象,使用对象的class文件可以反射获取
// 调用bind方法的应用层
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 代理类构造方法
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
// bind方法逻辑
Class cls = target.getClass();
ClassLoader classLoader = cls.getClassLoader();
Class[] interfaces = cls.getInterfaces(); // 决定了 $Proxy0 implement IOrderService
return Proxy.newProxyInstance(classLoader, interfaces,this);
突破口2 —— InvocationHandler
Proxy.newProxyInstance(,,this)
this 指的是 OrderServiceDynamicProxy implments InvocationHandler
public $Proxy0(InvocationHandler var1) {
super(var1);
}
public final int saveOrder(Order methodVar) throws Throwable {
// protected InvocationHandler h;
// todo h 是父类Proxy类的成员变量,也就是构造时传入的 OrderServiceDynamicProxy
return (Integer) super.h.invoke(this, m3, new Object[]{methodVar});
}
super.h.invoke(this, m3, new Object[]{methodVar} )
等价于
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{methodVar})
则应用层
public class Test {
public static void main(String[] args) throws Throwable {
IOrderService orderServiceDynamicProxy
= (IOrderService) new OrderServiceDynamicProxy( new OrderServiceImpl()).bind();
// 数据准备
Order order = new Order();
// 使用动态代理存数据
orderServiceDynamicProxy.saveOrder(order);
}
}
orderServiceDynamicProxy.saveOrder(order)
内部调用的是
OrderServiceDynamicProxy.invoke(this, m3, new Object[]{order})
突破口3 —— OrderServiceDynamicProxy.invoke 与 动态代理的关系
动态代理类只要实现Invoke方法,并且确保method.invoke(target, args)即可代理target的所有方法, 还可以加上自己的前置和后置处理,强制代理类实现的原因是:
$Proxy0 的生成模板有super.h.invoke(this, m3, new Object[]{…args})
所以应用层需要适配这个实现
/**
* 核心方法 -- 需要debug确定该方法的作用
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object argObject = args[0];
beforeMethod(argObject);
Object object = method.invoke(target, args);
afterMethod();
return object;
}
总结
动态代理的实现核心是 借助 $Proxy0 在运行时生成一个被代理类的class文件,代理类不需要在编译时写死被代理类
实现 InvocationHandler 是让动态代理强制适配 $Proxy0 的生成规则
能够做到在应用层动态决定被代理类,起到决定性的技术是反射