找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1230

积分

0

好友

174

主题
发表于 4 天前 | 查看: 14| 回复: 0

做Spring开发时,@Transactional@Async这些注解的动态代理是如何被创建的?Spring的ProxyFactory作为动态代理的核心工厂,封装了从配置到生成的全过程。本文将通过源码分析,揭示其内部工作机制与代理类型的决策逻辑。

一、ProxyFactory的核心定位:动态代理的“总指挥”

在Spring的AOP体系中,ProxyFactory是一个入口级的工具类。它封装了创建代理对象所需的所有流程,从配置Advisor、TargetSource,到最终生成代理实例,都由它统一调度和管理。

从类继承关系来看,ProxyFactory继承自ProxyCreatorSupport,而ProxyCreatorSupport实现了Advised接口(用于维护代理的配置信息,如拦截器链、目标类等)。因此,ProxyFactory的核心能力在于整合“配置管理”与“代理生成”两大功能,是理解Java动态代理底层实现的关键入口。

二、ProxyFactory创建代理的核心流程:从配置到实例

ProxyFactory生成代理的入口是getProxy()方法,其核心逻辑非常清晰:

// ProxyFactory.java
public Object getProxy() {
    return createAopProxy().getProxy(); // 核心逻辑:创建AopProxy并生成代理
}
protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate(); // 初始化:解析Advisor、TargetSource等配置
    }
    return getAopProxyFactory().createAopProxy(this); // 委托给AopProxyFactory
}

这两行代码构成了ProxyFactory的“心脏”:

  1. createAopProxy():根据当前配置(如是否强制CGLIB、目标类是否为接口)创建具体的AopProxy实例(JDK动态代理或CGLIB代理的实现)。
  2. getProxy():通过上一步创建的AopProxy实例生成最终的代理对象。
1. activate():初始化配置

activate()方法负责将配置的Advisor、TargetSource等信息“装配”成可执行的拦截器链。例如,当我们调用proxyFactory.addAdvice(new LoggingAdvice())时,activate()方法会将Advice包装成Advisor,并最终解析为拦截器链。

// ProxyCreatorSupport.java
protected void activate() {
    this.active = true;
    // 初始化AdvisorChainFactory:用于生成拦截器链
    if (this.advisorChainFactory == null) {
        this.advisorChainFactory = new DefaultAdvisorChainFactory();
    }
}

三、DefaultAopProxyFactory:代理类型的“决策者”

ProxyFactory将代理类型的选择委托给DefaultAopProxyFactory。它的核心方法createAopProxy(AdvisedSupport config)决定了使用JDK动态代理还是CGLIB代理

// DefaultAopProxyFactory.java
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 判断是否需要CGLIB代理的三大条件
    if (config.isOptimize() // 1. 是否优化(优先CGLIB)
        || config.isProxyTargetClass() // 2. 是否强制代理目标类
        || hasNoUserSuppliedProxyInterfaces(config)) { // 3. 目标类是否没有实现接口
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class");
        }
        // 特殊情况:如果目标类本身就是接口或是代理类,仍使用JDK代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 默认情况下,使用CGLIB代理
        return new ObjenesisCglibAopProxy(config);
    } else {
        // 否则,使用JDK动态代理
        return new JdkDynamicAopProxy(config);
    }
}

这段代码清晰地回答了Spring何时使用JDK代理,何时使用CGLIB这一问题:

  • 优先使用JDK动态代理(基于接口)。
  • 当满足以下任一条件时,则使用CGLIB代理
    1. 配置了 proxyTargetClass = true(强制代理目标类本身)。
    2. 目标类没有实现任何接口。
    3. 配置了 optimize = true(优先性能优化,历史上更倾向CGLIB)。

四、JDK vs CGLIB:两种代理的底层实现差异

了解决策逻辑后,我们进一步深入两种代理的底层生成机制

1. JDK动态代理:基于接口的代理

JDK动态代理的实现类是JdkDynamicAopProxy,其核心方法是getProxy()

// JdkDynamicAopProxy.java
public Object getProxy(ClassLoader classLoader) {
    // 1. 补全代理接口(例如Advised接口,用于查询代理配置)
    Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
    // 2. 处理equals和hashCode方法
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 3. 调用JDK原生API生成代理实例
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

Proxy.newProxyInstance()是JDK提供的标准API,其第三个参数InvocationHandler是关键。JdkDynamicAopProxy自身就实现了InvocationHandler接口,因此当代理对象的方法被调用时,会触发其invoke()方法:

// JdkDynamicAopProxy.java (invoke方法核心逻辑)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    ...
    // 1. 获取拦截器链(例如@Transactional对应的事务拦截器)
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    // 2. 无拦截器:直接反射调用目标方法
    if (chain.isEmpty()) {
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
    } else {
        // 3. 有拦截器:执行拦截器链(事务的开启→执行目标方法→提交/回滚)
        invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        retVal = invocation.proceed(); // 链式调用
    }
    ...
}

invoke()方法的核心在于拦截器链的执行ReflectiveMethodInvocation.proceed()会依次执行链中的每个拦截器,最终调用目标方法,这就是Spring AOP机制中“环绕通知”的底层实现。

2. CGLIB动态代理:基于继承的代理

CGLIB代理的实现类是ObjenesisCglibAopProxy(Spring 4+引入,用于解决CGLIB无法代理无默认构造函数类的问题)。其核心是利用CGLIB的Enhancer类生成代理子类。

// ObjenesisCglibAopProxy.java
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
    enhancer.setInterceptDuringConstruction(false); // 构造方法不拦截
    // 根据是否有构造参数选择创建方式
    return (this.constructorArgs != null && this.constructorArgTypes != null) ?
            enhancer.create(this.constructorArgTypes, this.constructorArgs) : // 带参构造
            enhancer.create(); // 无参构造
}

CGLIB通过继承目标类来生成代理类(这是它能代理非接口方法的原因)。生成的代理类会重写所有非final方法,并将调用转发给MethodInterceptor。Spring的CglibAopProxy实现了该接口,其intercept()方法的执行逻辑与JDK代理的invoke()类似。

五、ProxyFactory的“隐藏技能”:自定义代理逻辑

除了默认的JDK/CGLIB代理,ProxyFactory支持自定义AopProxy。你可以通过实现AopProxyFactory接口,完全控制代理的生成逻辑,这体现了Spring框架强大的扩展性。

// 自定义AopProxyFactory示例
public class CustomAopProxyFactory implements AopProxyFactory {
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 自定义逻辑:例如,始终返回CGLIB代理
        return new ObjenesisCglibAopProxy(config);
    }
}
// 使用自定义Factory
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setAopProxyFactory(new CustomAopProxyFactory());
Object proxy = proxyFactory.getProxy();

六、ProxyFactory的“避坑指南”

  1. 不要代理final类/方法:CGLIB通过继承生成代理,final类无法被继承,final方法无法被重写。
  2. 注意TargetSource的生命周期:如果TargetSource被配置为Prototype(多例),ProxyFactory每次调用都会创建新的目标对象,需注意资源及时释放。
  3. 正确使用exposeProxy属性:如果需要在目标方法内部获取当前的代理对象(例如通过AopContext.getCurrentProxy()调用自身另一个被AOP管理的方法),必须设置proxyFactory.setExposeProxy(true)。这涉及到代理模式在复杂场景下的应用。

结尾

通过源码分析可以看出,ProxyFactory的核心逻辑并不复杂,遵循着“配置→决策→生成”的清晰流程。理解它,不仅能让你深入掌握Spring AOP的底层原理,也为你设计和实现自己的代理机制提供了清晰的思路。




上一篇:Nginx配置与部署完全指南:从静态站点搭建到日志管理实战
下一篇:MySQL InnoDB存储引擎碎片整理全攻略:原理、实战与高并发场景避坑
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-17 18:47 , Processed in 0.108865 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表