JDK动态代理的实现原理

1、示例demo

  • 计算接口
package com.zcqby.proxy.jdk;

public interface Calculator {

    public int add(int i, int j);

    public int sub(int i, int j);

    public int mult(int i, int j);

    public int div(int i, int j);
}
  • 实现类
package com.zcqby.proxy.jdk;

public class MyCalculator implements Calculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mult(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }
}
  • 代理类
package com.zcqby.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class CalculatorProxy {
    public static Calculator getProxy(final Calculator calculator){
        ClassLoader loader = calculator.getClass().getClassLoader();
        Class<?>[] interfaces = calculator.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    result = method.invoke(calculator, args);
                } catch (Exception e) {
                } finally {
                }
                return result;
            }
        };
        Object proxy = Proxy.newProxyInstance(loader, interfaces, h);
        return (Calculator) proxy;
    }
}
  • 测试类
package com.zcqby.proxy.jdk;

public class Test {
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Calculator proxy = CalculatorProxy.getProxy(new MyCalculator());
        proxy.add(1,1);
        proxy.div(10,100);
        System.out.println(proxy.getClass());
    }
}

2、源码跟踪

image-20220705193836042

image-20220705194018318

image-20220705194142592

  • 上图的注释部分, 我们可以大致知道, 就是 如果proxyClassCache 缓存中已经有了这个对象,那么我们就直接从缓存中获取对象;
  • 如果缓存中没有该对象, 则我们就需要通过 ProxyClassFactory 代理类工厂去创建对象。

image-20220705194622139

image-20220705194840236

  • 值得注意的是, 这边的 map 的数据结构是 是 map里面套map,并且使用的 ConcurrentMap

image-20220705200509984

如上图所示, 动态代理的class文件生成的主要实现, 就是上图所示的ProxyClassFactory 中,这里就是真实的创建动态代理生成的class文件的地方。

image-20220705201122292

image-20220705201505461

image-20220705201650758

image-20220705201823131

image-20220705203428327

image-20220705203651872

image-20220705204120279

image-20220705204213711

image-20220705204537011

image-20220705204847326

image-20220705205723261

image-20220705210011729

image-20220705210128828

image-20220705210411402

image-20220705210803756

image-20220705210914209

image-20220705211047427

image-20220705211256195

执行完上述逻辑后, 不断返回个上层调用者, 最终到如下图的位置的时候, 就有了代理类

image-20220705211457302

image-20220705211554327

image-20220705211804746

image-20220705212156706

image-20220705212559992

posted on 2022-07-05 21:33  QzkRainPig  阅读(302)  评论(0编辑  收藏  举报