spring-projects / spring-projects/spring-framework

BeanCurrentlyInCreationException with DelegatingWebFluxConfiguration

Open
#25,166 1 comment 5 reactions 1 assignee View on GitHub

@rstoyanchev is already working on this.

Since Jun 7, 2022.

in: web type: enhancement
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

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:

  1. authenticationPrincipalArgumentResolver is requested
  2. It triggers the creation of ReactiveAdapterRegistry which is a dependant bean
  3. In order to create ReactiveAdapterRegistry, DelegatingWebFluxConfiguration needs to be created which requires all WebFluxConfigurer instances to be wired into it.
  4. This tries to retrieve all WebFluxConfigurer instances. One of which is authenticationPrincipalArgumentResolverConfigurer which provides our authenticationPrincipalArgumentResolver bean as an argument resolver.
  5. This requests authenticationPrincipalArgumentResolver which 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.

  1. The first drawback is that while it reduces the likelihood of an error, it doesn't remove the cycle between ArgumentResolverConfig and WebFluxConfigurationSupport.
  2. Second, it requires every AuthenticationPrincipalArgumentResolver configuration needing ReactiveAdapterRegistry (I'd argue that is pretty much every AuthenticationPrincipalArgumentResolver) to have the burden of fixing the issue rather than decoupling the beans (HandlerMethodArgumentResolver and ReactiveAdapterRegistry) 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 https://github.com/spring-projects/spring-boot/issues/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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.