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

jsa*_*ler 11 java spring spring-boot

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

@Configuration(proxyBeanMethods=false)
public class SomeAutoConfiguration {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

以下是我的问题:

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

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

Gee*_*nte 17

像这样的东西:

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,proxyBeanMethods 将确保“sharedService”方法将被拦截并重用其结果。如果按照普通的java逻辑,在调用serviceA()和serviceB()时,会有两个不同的ServiceC实例,直接调用sharedService()时,会创建第三个实例。然后代理拦截器会保证实际的方法只被调用一次,所以只创建了一个共享ServiceC的实例,ServiceA和ServiceB都会得到共享实例。

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

一种方法是通过方法参数而不是嵌套方法调用自动连接服务。它在普通 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @TobiAkinyemi proxyBeanMethods=false 是一个性能提升,特别是对于有很多 @Configuration 类的库,比如 spring-boot 的内部库。他们无法将其设为默认值,因为这会破坏向后兼容性。请参阅原始问题中的链接。 (4认同)
  • @DennisC 请参阅 https://github.com/spring-projects/spring-boot/issues/9068#issuecomment-461520814,他们在其中使用 Spring Boot Webflux 示例对其进行了测试。 (4认同)
  • 为什么一回合会设置 `proxyBeanMethods=false`?即有人“想要”为每个服务生成一个新的 bean“sharedService”bean 吗?看起来 Spring 的想法是拥有一个共享服务 (2认同)