作用:用于控制配置类的代理行为,确定配置类中的 @Bean 方法是否被代理,从而影响 Bean 的创建和管理方式
比较
proxyBeanMethods = true
- 默认行为: 当 proxyBeanMethods 设置为 true(默认值)时,Spring 会为配置类创建一个代理对象。这个代理对象确保在调用 @Bean 方法时,如果该 Bean 已经在 Spring 容器中存在,则返回容器中的单例实例,而不是每次都创建一个新的实例。
- 保证单例: 这种方式确保了配置类中的 @Bean 方法是幂等的,即无论调用多少次,返回的都是同一个实例。这对依赖注入和单例模式非常重要。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyController myController() {
// 调用 myService() 方法时,返回的是 Spring 容器中的 MyService 实例,而不是新创建的实例
return new MyController(myService());
}
}
proxyBeanMethods = false
- 禁用代理: 当 proxyBeanMethods 设置为 false 时,Spring 不会为配置类创建代理。这意味着每次调用 @Bean 方法时,都会创建一个新的实例,而不是返回容器中的单例实例。
- 适用场景: 如果你不需要 @Bean 方法之间的依赖关系,并且想要优化性能以避免代理开销,可以将 proxyBeanMethods 设置为 false。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
@Bean
public MyController myController() {
// 调用 myService() 方法时,每次都会创建一个新的 MyService 实例
return new MyController(myService());
}
}
在这个配置中,每次调用 myService() 方法时,都会创建一个新的 MyService 实例。如果 myController() 方法被频繁调用,将会导致大量的 MyService 实例被创建。
proxyBeanMethods = false为什么能优化性能
proxyBeanMethods = true(默认值)
- 代理开销: 当 proxyBeanMethods 设置为 true 时,Spring 会为配置类创建一个 CGLIB 代理。这个代理会拦截对 @Bean 方法的调用,以确保在方法之间引用同一个 Bean 实例。虽然这种代理机制确保了 Bean 的单例性和依赖关系,但它也引入了一些额外的开销。
- 运行时检查: 每次调用 @Bean 方法时,代理对象会进行检查,以决定是返回现有的 Bean 实例还是创建一个新的实例。这个过程涉及到运行时反射和方法调用的拦截,都会消耗一定的资源。
proxyBeanMethods = false
- 无代理开销: 当 proxyBeanMethods 设置为 false 时,Spring 不会为配置类创建代理。这意味着配置类中的 @Bean 方法是普通的 Java 方法,没有代理对象来拦截和处理这些方法调用。
- 直接调用: @Bean 方法的调用是直接的,没有额外的检查和拦截。这减少了运行时的开销,因为不再需要代理机制的参与。
- 编译时优化: 因为没有代理,Java 编译器和 JVM 可以对配置类和 @Bean 方法进行更多的优化,例如方法内联和其他 JIT 编译优化。
proxyBeanMethods = false时,创建对象也是要消耗性能的
代理开销 vs. 对象创建开销
- 代理开销(proxyBeanMethods = true): Spring 通过创建 CGLIB 代理来管理配置类中的 @Bean 方法。这确保了方法调用返回的是容器中的单例实例,但代理的创建和运行时拦截会引入额外的开销。
- 对象创建开销(proxyBeanMethods = false): 每次调用 @Bean 方法时都会创建一个新的对象实例。虽然避免了代理相关的开销,但频繁的对象创建也会增加内存使用和垃圾回收的负担。
适用场景
- 频繁调用 @Bean 方法且需要单例: 如果配置类中的 @Bean 方法被频繁调用,并且这些方法之间存在依赖关系,使用 proxyBeanMethods = true 更加合适。这种情况下,代理开销可以接受,因为它确保了方法调用的幂等性和单例性。
- 简单配置类或不需要单例: 如果配置类中的 @Bean 方法不会频繁调用,或者每次调用返回的新实例不会对应用的性能造成显著影响,可以使用 proxyBeanMethods = false。这种配置避免了代理开销,适用于简单的、独立的 Bean 创建场景。