When looking at springs autoconfigure source code it seems that every auto-configuration class sets proxyBeanMethods = false
.
@Configuration(proxyBeanMethods=false)
public class SomeAutoConfiguration {
...
}
The javadoc gives a detailed explanation for this particular field:
Specify whether {@code @Bean} methods should get proxied in order to enforce bean lifecycle behavior, e.g. to return shared singleton bean instances even in case of direct {@code @Bean} method calls in user code. (...) If this is not needed since each of this particular configuration's {@code @Bean} methods is self-contained and designed as a plain factory method for container use, switch this flag to {@code false} in order to avoid CGLIB subclass processing.(...)
After reading this I'm still confused when it is better setting it to false.
Here are my questions:
Update:
Found two issues on github that give some explanation why it is false
on most auto-configutation classes:
One of the most important annotations in spring is @Configuration annotation which indicates that the class has @Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application. This annotation is part of the spring core framework.
proxyBeanMethods allows you to invoke one method marked as Bean from another one declared in the same configuration class.
It is a method-level annotation. During Java configuration ( @Configuration ), the method is executed and its return value is registered as a bean within a BeanFactory .
This is because Spring creates a CGLIB proxy around the @Configuration classes. The calls are intercepted and then Spring checks the container before creating a new bean for us. So to reiterate, when we invoke postRepository() three times, only the first invocation creates a Spring bean.
Something like this:
@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();
}
}
Here, the proxyBeanMethods will assure that the 'sharedService' method will be intercepted and its result re-used. If you would follow the normal java logic, when calling serviceA() and serviceB(), there would be two different instances of ServiceC, and when calling sharedService() directly, a third instance would be created. Then proxy interceptor will make sure the actual method is only called once, so only one instance of the shared ServiceC is created, and both ServiceA and ServiceB will get the shared instance.
However proxyBeanMethods=true has a performance cost during startup, especially for libraries with a lot of @ Configuration classes, like spring-boot's internal libraries. See e.g. https://github.com/spring-projects/spring-boot/issues/9068#issuecomment-461520814 for the impact on Spring WebFlux. They couldn't change it to false by default, since that would break backwards compatibility. See links in the original question.
You can use different configuration patterns to avoid this, which is probably what auto-configuration classes do.
One way to do this is auto-wiring the service via method parameters instead of nested method calls. It makes less sence in normal Java, but it works in Spring configurations:
@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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With