何时在Springs@Configuration中将proxyBeanMethods设置为false



当查看springs自动配置源代码时,似乎每个自动配置类都设置了proxyBeanMethods = false

@Configuration(proxyBeanMethods=false)
public class SomeAutoConfiguration {
...
}

javadoc对这个特定的字段给出了详细的解释:

指定是否应该代理{@code@Bean}方法以强制执行bean生命周期行为,例如甚至返回共享的单例bean实例在用户代码中直接调用{@code@Bean}方法的情况下。(…(如果这是不需要的,因为每个特定配置的{@code@Bean}方法是自包含的并且被设计为用于容器使用的普通工厂方法,将此标志切换为{@code-false},以避免CGLIB子类处理。(…(

看完这篇文章后,我仍然很困惑什么时候最好将其设置为false。

以下是我的问题:

  • 有人能举一个具体的例子说明这个领域应该是真的吗?并解释为什么
  • 为什么在自动配置类上将此字段设置为false

更新:在github上发现了两个问题,这两个问题解释了为什么它在大多数自动配置类上是false

  • https://github.com/spring-projects/spring-boot/issues/9068
  • https://github.com/spring-projects/spring-framework/issues/22461

类似这样的东西:

@Configuration(proxyBeanMethods=true)
public class SomeConfiguration {
@Bean
ServiceA serviceA(){
return new ServiceA(sharedService());
}
@Bean
ServiceB serviceB(){
return new ServiceB(sharedService());
}
@Bean
ServiceC sharedService(){
return new ServiceC();
}
}

在这里,proxyBeanMethod将确保"sharedService"方法将被截获,并重新使用其结果。如果您遵循正常的java逻辑,当调用serviceA((和serviceB((时,会有两个不同的ServiceC实例,而当直接调用sharedService((时会创建第三个实例。然后,代理拦截器将确保实际方法只调用一次,因此只创建共享ServiceC的一个实例,ServiceA和ServiceB都将获得共享实例。

然而,proxyBeanMethods=true在启动过程中会产生性能成本,尤其是对于具有大量@Configuration类的库,如spring-boot的内部库。参见例如。https://github.com/spring-projects/spring-boot/issues/9068#issuecomment-461520814对Spring WebFlux的影响。默认情况下,他们不能将其更改为false,因为这会破坏向后兼容性。请参阅原始问题中的链接。

您可以使用不同的配置模式来避免这种情况,这可能就是自动配置类所做的

一种方法是通过方法参数而不是嵌套的方法调用来自动连接服务。它在普通Java中的意义不大,但在Spring配置中有效:

@Configuration(proxyBeanMethods=false)
public class SomeSmarterConfiguration {
@Bean
ServiceC sharedService(){
return new ServiceC();
}
@Bean
ServiceA serviceA(ServiceC sharedService){
return new ServiceA(sharedService);
}
@Bean
ServiceB serviceB(ServiceC sharedService){
return new ServiceB(sharedService);
}
}

Spring在5.2版中引入了proxyBeanMethod。proxyBeansMethods的默认值为true。这意味着默认情况下,将为使用@Configuration配置的类生成代理对象。在Springboot版本2及更高版本中,所有AutoConfiguration类都使用@Configuration(proxyBeanMethods=false(进行配置。这是因为SpringBoot中广泛使用了自动配置功能。生成代理对象将增加spring的启动时间,并增加代理部分的对象内存。最佳实践是使用@configuration(proxyBeanMethods=false(注释配置类

相关内容

最新更新