【JDK动态代理源码梳理】

JDK动态代理源码梳理文档

一、整体源码调用链路

Proxy.newProxyInstance() → getProxyConstructor() → proxyCache.computeIfAbsent() → Memoizer.get() → ProxyBuilder.build() → cons.newInstance(h)

1、入口方法 newProxyInstance

java 复制代码
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h) {
    Objects.requireNonNull(h);

    @SuppressWarnings("removal")
    final Class<?> caller = System.getSecurityManager() == null
                                ? null
                                : Reflection.getCallerClass();

    Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
    return newProxyInstance(caller, cons, h);
}
  1. @CallerSensitive:JVM标识,允许native方法Reflection.getCallerClass()读取调用栈获取调用类;
  2. caller赋值逻辑:无安全管理器(默认环境) → caller = null,跳过全部权限校验;开启安全管理器才获取调用方Class做权限校验
  3. 99.9%业务环境caller=null,直接放行代理类生成。

2、getProxyConstructor(缓存分支分发)

区分单个接口/多个接口两条分支,逻辑一致:

  • caller != null:执行checkProxyAccess权限校验;
  • caller = null:跳过权限校验,进入缓存逻辑;
  • 依托proxyCache做代理类缓存,computeIfAbsent实现「有缓存直接取构造器,无缓存则构建ProxyBuilder生成代理类」。

3、computeIfAbsent(高并发缓存自旋逻辑)

  1. 依托ConcurrentHashMap做代理构造器缓存,while(true)自旋处理多线程并发创建同一个代理类竞争;
  2. Memoizer为延迟创建任务封装:缓存不存在时初始化Memoizer,putIfAbsent抢占缓存位,抢占成功执行生成逻辑;
  3. 生成异常则移除缓存key,后续请求复用异常结果。

4、Memoizer.get()(单例生成、DCL+同步锁)

java 复制代码
public V get() throws RecursiveInvocationException {
    V v = this.v;
    if (v != null) return v;
    Throwable t = this.t;
    if (t == null) {
        synchronized (this) {
            if ((v = this.v) == null && (t = this.t) == null) {
                if (inCall) {
                    throw new RecursiveInvocationException();
                }
                inCall = true;
                try {
                    this.v = v = Objects.requireNonNull(
                        mappingFunction.apply(cl, clv));
                } catch (Throwable x) {
                    this.t = t = x;
                } finally {
                    inCall = false;
                }
            }
        }
    }
    if (v != null) return v;
    // 异常分类抛出
    if (t instanceof Error) throw (Error) t;
    else if (t instanceof RuntimeException) throw (RuntimeException) t;
    else throw new UndeclaredThrowableException(t);
}
  • DCL双重检查+synchronized锁:保证同一个接口+类加载器的代理类只生成一次
  • inCall标记:防止代理生成时递归调用造成死循环;
  • 生成结果/异常均缓存,后续线程直接复用结果或异常。

5、ProxyBuilder.build()(生成代理Class、获取构造器)

java 复制代码
Constructor<?> build() {
    Class<?> proxyClass = defineProxyClass(module, interfaces);
    // JDK9+模块权限断言
    assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Proxy.class.getModule());

    final Constructor<?> cons;
    try {
        cons = proxyClass.getConstructor(constructorParams);
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
    // 特权放行,放开构造器访问权限
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {
            cons.setAccessible(true);
            return null;
        }
    });
    return cons;
}
  1. defineProxyClass:底层拼接字节码、Unsafe加载Class,生成$ProxyN代理类;
  2. 获取入参为InvocationHandler的唯一构造方法,特权修改访问权限;
  3. 返回构造器,供反射实例化。

6、实例化:cons.newInstance(new Object\[\]{h})

反射调用代理类构造方法,将自定义InvocationHandler传入,最终生成代理对象,等价代码:new $Proxy0(h)

二、运行时生成完整代理类$Proxy0示例

java 复制代码
public final class $Proxy0 extends Proxy implements UserService {
    private static Method mAdd;
    private static Method mDelete;
    private static Method mEquals;
    private static Method mToString;
    private static Method mHashCode;

    static {
        try {
            mAdd = Class.forName("UserService").getMethod("add");
            mDelete = Class.forName("UserService").getMethod("delete");
            mEquals = Object.class.getMethod("equals", Object.class);
            mToString = Object.class.getMethod("toString");
            mHashCode = Object.class.getMethod("hashCode");
        } catch (Exception e) {
            throw new NoClassDefFoundError(e.getMessage());
        }
    }

    public $Proxy0(InvocationHandler var1) {
        super(var1);
    }

    public final void add() {
        try {
            super.h.invoke(this, mAdd, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    public final void delete() {
        try {
            super.h.invoke(this, mDelete, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    public final boolean equals(Object o) {
        return (Boolean) super.h.invoke(this, mEquals, new Object[]{o});
    }
    public final String toString() {
        return (String) super.h.invoke(this, mToString, null);
    }
    public final int hashCode() {
        return (Integer) super.h.invoke(this, mHashCode, null);
    }
}

核心:代理类无业务实现,所有接口方法+Object三大方法全部转发至InvocationHandler.invoke()

三、自定义InvocationHandler两大关键点

  1. 必须持有目标对象target引用
java 复制代码
class MyHandler implements InvocationHandler {
    private final Object target;
    public MyHandler(Object target) { this.target = target; }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强
        Object res = method.invoke(target, args); // 调用真实目标方法
        // 后置增强
        return res;
    }
}

代理壳子只做转发,依靠target执行原生业务逻辑。

  1. 多方法差异化增强,需要在invoke内判断Method
    原生硬编码弊端:大量if-else、耦合严重、不易扩展;Spring AOP通过Pointcut切点匹配、拦截器链优化该痛点,替代手动判断Method。

四、核心总结

  1. JDK动态代理本质:运行时动态生成实现目标接口的字节码类,所有方法转发至InvocationHandler;
  2. 缓存设计:JDK内置多级缓存+锁控制,避免重复生成代理类,节省JVM内存;
  3. 设计短板:仅支持接口代理、差异化增强需手动判断方法,催生Spring AOP封装优化。
相关推荐
Resky08181 小时前
什么是 Spring IOC:倒过来让容器帮你 new,而不是你到处 new
java·spring
AI进阶客栈1 小时前
开源 MQ Master:Spring Boot 统一管控 5 大消息队列
spring boot·后端·开源
勇哥java实战分享1 小时前
AI 降低了『写代码』的门槛,但是没有降低『软件开发』的复杂度
后端
暗夜猎手-大魔王1 小时前
转载--Hermes Agent 10 | 7 层安全防线:从用户授权到输入净化
java·数据库·安全
idolao3 小时前
Oligo 7.60 安装教程:引物设计+Java 环境配置
java·开发语言
做个文艺程序员6 小时前
第04篇:K8s 弹性伸缩实战:HPA、VPA、KEDA——Java SaaS 应对流量洪峰的秘密武器
java·容器·kubernetes·弹性伸缩·自动扩容·ai 推理伸缩
木雷坞7 小时前
Go 项目实战:用 MLiev IAM 落地企业认证中心
后端·golang·认证
石山代码10 小时前
ArrayList / HashMap / ConcurrentHashMap
java·开发语言