You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In our project, we use a custom Scope that can be controlled to some degree by the application. The Bean is declared in a @Configuration class using the @Bean annotation. The same class contains the CustomScopeConfigurer declaration referencing the Scope by method name.
@Configuration
public class Configuration
{
@Bean
static CustomScope getCustomScope()
{
return new CustomScope();
}
@Bean
static CustomScopeConfigurer getCustomScopeConfigurer()
{
CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
customScopeConfigurer.addScope("customScope", getCustomScope());
return customScopeConfigurer;
}
}
To control the custom Scope, we tried to inject it using @Autowired. This resulted in a new Bean being created. To access the Bean being used internally, we have to inject the ApplicationContext, retrieve the BeanFactory, then the registered Scope.
Usually, one would expect to have easy access to the custom Scope, since it is declared in the same @Configuration class. But apparently it lives in a completely separate Context. I can access it, however, via public methods.
I would highly recommend to change this, and add a word or two to the Javadocs. Either have it in a separate Context and not accessible, or allow access and make it injectable. The current behavior is inconsistent and not documented, as far as I can tell.
The root of the problem is the static nature of those @Bean methods: For regular, non-static @Bean methods, the container overrides such methods to allow for calls between @Bean methods, preserving the Spring scoping semantics that way. However, due to the technical mechanism used (subclassing via CGLIB), this cannot work for static methods.
So in your scenario, the getCustomScope() call in the getCustomScopeConfigurer method simply calls the other method without any interception or container treatment, i.e. with regular Java method call semantics. It'll get a fresh CustomScope instance that way which the container is not aware of. If you're then also requesting a CustomScope via the container, you'll get a managed singleton bean according to the @Bean getCustomScope declaration. Unfortunately, that managed singleton is different from the instance used by your CustomScopeConfigurer.
I hope the explanation above makes sense. Point taken that this isn't properly documented, so I'm turning this into a documentation task.
The next question is: Can I turn it into a non-static method safely? There is a warning issued that some annotations will not work if the CustomScopeConfigurer bean method is not static. Again, it is not exactly clear to me what the intended way is.
It's generally advisable to declare post-processor beans via static {{@Bean} methods. I've added a basic discussion of static {{@Bean} methods to the reference documentation now, including a note on post-processor beans.
With static methods, you could simply keep the CustomScope instance in a static field, expose it via a static getCustomScope method and also use the field in your CustomScopeConfigurer factory method.
Uh oh!
There was an error while loading. Please reload this page.
Johannes Zick opened SPR-13118 and commented
In our project, we use a custom
Scope
that can be controlled to some degree by the application. The Bean is declared in a@Configuration
class using the@Bean
annotation. The same class contains theCustomScopeConfigurer
declaration referencing theScope
by method name.To control the custom
Scope
, we tried to inject it using@Autowired
. This resulted in a new Bean being created. To access the Bean being used internally, we have to inject theApplicationContext
, retrieve theBeanFactory
, then the registeredScope
.Usually, one would expect to have easy access to the custom
Scope
, since it is declared in the same@Configuration
class. But apparently it lives in a completely separate Context. I can access it, however, via public methods.I would highly recommend to change this, and add a word or two to the Javadocs. Either have it in a separate
Context
and not accessible, or allow access and make it injectable. The current behavior is inconsistent and not documented, as far as I can tell.Affects: 4.1.5
Issue Links:
@Configuration
classes with post-processor definitionsReferenced from: commits f58e1db
The text was updated successfully, but these errors were encountered: