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

2022-09-03 05:27:00

在查看弹簧自动配置源代码时,似乎每个自动配置类都设置了。proxyBeanMethods = false

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

javadoc给出了这个特定字段的详细说明:

指定 {@code @Bean} 方法是否应进行代理以强制 Bean 生命周期行为,例如,即使在用户代码中直接调用 {@code @Bean} 方法的情况下,也要返回共享的单例 Bean 实例。(...)如果由于每个特定配置的 {@code @Bean} 方法都是独立的,并且设计为容器使用的普通工厂方法,因此不需要这样做,请将此标志切换为 {@code false},以避免 CGLIB 子类处理。(...)

阅读本文后,当最好将其设置为false时,我仍然感到困惑。

以下是我的问题:

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

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


答案 1

像这样:

@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();
    }
}

在这里,proxyBeanMethods将确保“sharedService”方法将被拦截并重用其结果。如果您遵循正常的java逻辑,那么在调用serviceA()和serviceB()时,将有两个不同的ServiceC实例,并且当直接调用shareservice()时,将创建第三个实例。然后,代理拦截器将确保实际方法只调用一次,因此仅创建共享 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);
    }
}

答案 2

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


推荐