-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Description
DelegatingWebFluxConfiguration can trigger BeanCurrentlyInCreationException under a few circumstances.
ReactiveAdapterRegistry
The first problem is that it is difficult to provide a HandlerMethodArgumentResolver that needs the ReactiveAdapterRegistry because this can cause a cycle depending on the order the beans are instantiated. For example, this test produces a cycle:
authenticationPrincipalArgumentResolveris requested- It triggers the creation of
ReactiveAdapterRegistrywhich is a dependant bean - In order to create
ReactiveAdapterRegistry,DelegatingWebFluxConfigurationneeds to be created which requires allWebFluxConfigurerinstances to be wired into it. - This tries to retrieve all
WebFluxConfigurerinstances. One of which isauthenticationPrincipalArgumentResolverConfigurerwhich provides ourauthenticationPrincipalArgumentResolverbean as an argument resolver. - This requests
authenticationPrincipalArgumentResolverwhich is a cycle
One option to make this less likely to happen is to define authenticationPrincipalArgumentResolverConfigurer as:
@Bean
public WebFluxConfigurer authenticationPrincipalArgumentResolverConfigurer(
ObjectProvider<AuthenticationPrincipalArgumentResolver> authenticationPrincipalArgumentResolver) {
return new WebFluxConfigurer() {
@Override
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
configurer.addCustomResolver(authenticationPrincipalArgumentResolver.getObject());
}
};
}This delays the lookup of AuthenticationPrincipalArgumentResolver. However, this has a few drawbacks.
- The first drawback is that while it reduces the likelihood of an error, it doesn't remove the cycle between
ArgumentResolverConfigandWebFluxConfigurationSupport. - Second, it requires every
AuthenticationPrincipalArgumentResolverconfiguration needingReactiveAdapterRegistry(I'd argue that is pretty much everyAuthenticationPrincipalArgumentResolver) to have the burden of fixing the issue rather than decoupling the beans (HandlerMethodArgumentResolverandReactiveAdapterRegistry) that are likely dependant on one another).
We could move the delay inside DelegatingWebFluxConfiguration by autowiring ObjectProvider<WebFluxConfigurer> instead. However, this only fixes the second problem and leaves the cycle present.
Another option is to make the definition of ReactiveAdapterRegistry a static method. This would ensure that DelegatingWebFluxConfiguration does not need to be instantiated. Yet another option would be to move ReactiveAdapterRegistry to another configuration, but this could break other applications.
ResourceUrlProvider Can Cause Early Initialization of DelegatingWebFluxConfiguration
ResourceUrlProvider implements ApplicationListener which can trigger early initialization of DelegatingWebFluxConfiguration. As soon as an ApplicationEvent is published, the ApplicationListeners need initialized. Since ResourceUrlProvider is defined by DelegatingWebFluxConfiguration it initializes DelegatingWebFluxConfiguration and all of its dependant beans very early on.
This is what is why the originally reported issue would happen in Boot 2.3.0 and not in previous versions. Specifically the changes for spring-projects/spring-boot#21325 moved the publishing of the ReactiveWebServerInitializedEvent from finishRefresh to SmartLifecycle's start method. This changed the order that DelegatingWebFluxConfiguration was created and triggered the bean cycle to happen.
One solution is to move the ResourceUrlProvider bean definition to a static method.
Related Issues