【java_设计模式】jdk动态代理原码解析,debug 获取 $proxy0

38 篇文章 0 订阅
23 篇文章 2 订阅

普通测试场景

  • 业务场景
    保存订单信息
  • 分层模型
    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

  1. 返回值起源 – 确定返回值
    return Proxy.newProxyInstance(classLoader, interfaces,this)

    Proxy.newProxyInstance 返回的是 $Proxy0对象
    在这里插入图片描述

  2. 返回值追踪 – 定位类
    Proxy类拥有创造前缀为$Proxy 的工厂内部类(jdk1.8)

    确定返回值来源类: java.lang.reflect.Proxy.ProxyClassFactory

    在这里插入图片描述

  3. 返回值追踪 – 定位语句

    639行出现了一个字节数组,为proxyClassFile,几乎能断定这是动态生成的 $proxy0 字节码文件
    在这里插入图片描述


  1. 使用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 的生成规则
能够做到在应用层动态决定被代理类,起到决定性的技术是反射

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值