proxy-target-class
含义
proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。
- true,则是基于类的代理将起作用(需要cglib库),
- false或者省略这个属性,则标准的JDK 基于接口的代理将起作用。
但是,即使设置为false,如果目标类没有生命接口,则Spring将自动使用CGLib动态代理。
用大白话来说,就是当要使用实现了某个接口的类,让Spring来生成bean时,会使用aop动态代理技术,生成代理类。此时,程序需要知道,采用哪一种代理技术,是CGLIB代理还是JDK代理。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
CGLIB(Code Generation Library),是一个代码生成的类库,是利用asm开源包,可以在运行时动态的生成某个类的子类。注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
示例
在TransactionAutoConfiguration
中,有如下代码:
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
可以看到:
- proxy-target-class为false,那么启用JdkDynamicAutoProxyConfiguration
- proxy-target-class为true,那么启用CglibAutoProxyConfiguration
proxyBeanMethods
一、proxyBeanMethods
属性的含义
- 代理机制
-
当
proxyBeanMethods = true
(默认值),Spring会通过CGLIB为配置类生成代理类,拦截@Bean
方法的调用,确保每次调用都返回容器内的单例Bean -
当
proxyBeanMethods = false
,配置类不会被代理,@Bean
方法作为普通工厂方法执行,每次调用可能生成新对象(但注册到容器的Bean仍为单例)
- 模式对比
-
Full模式(proxyBeanMethods = true)
-
保证单例性:通过代理拦截方法调用,确保同一配置类中
@Bean
方法返回的实例是容器中的唯一对象 -
支持Bean生命周期行为:如
@PostConstruct
、@Destroy
等注解生效
-
-
Lite模式(proxyBeanMethods = false)
-
无代理:方法调用直接执行,不通过容器,可能导致同一配置类中方法调用生成新对象
-
性能优化:避免生成CGLIB代理类,减少启动时间和内存占用
-
二、proxyBeanMethods
的作用
- 性能优化
- 在Lite模式下,SpringBoot跳过代理类的生成,显著提升启动速度,尤其适用于大量配置类的场景(如SpringBoot的自动配置类)
- 单例控制
- Full模式通过代理确保Bean的单例性,而Lite模式下,若直接在配置类内部调用
@Bean
方法,可能生成多个实例(但通过容器获取的Bean仍是单例)
- 方法调用限制
- Full模式允许
@Bean
方法之间相互调用(通过容器获取依赖),而Lite模式下需通过参数传递依赖,否则会导致多次实例化
- 灵活性与限制
- Lite模式支持将配置类作为普通类使用,允许
@Bean
方法为private
或final
,而Full模式因代理限制不允许这些修饰符
三、适用场景
- 使用Full模式的场景
-
配置类中
@Bean
方法存在相互依赖(需通过方法调用获取其他Bean) -
需要保证Bean生命周期行为(如初始化/销毁回调)
- 使用Lite模式的场景
-
@Bean
方法之间无依赖,且追求启动性能优化(如SpringBoot自动配置类) -
需要将配置类作为普通工具类使用(如静态工厂方法)
四、示例说明
@Configuration(proxyBeanMethods = false)
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean(); // 直接调用会生成新对象
}
@Bean
public User user() {
// Lite模式下需通过参数注入依赖,否则会创建新实例
return new User(myBean());
}
}
输出分析:若在Lite模式下调用myBean()两次,会触发两次构造函数,生成两个对象;但通过容器获取的myBean始终是单例。
五、总结
-
核心权衡:在单例安全性与性能之间选择。
-
推荐实践:无依赖的配置类优先使用Lite模式,复杂依赖场景使用Full模式
-
SpringBoot默认策略:自动配置类普遍采用
proxyBeanMethods = false
,以减少启动开销