Description

Spring can't distinguish bean types of RequestMappingHandlerMapping and its subtype ControllerEndpointHandlerMapping when a custom configuration using RequestMappingHandlerMapping runs before the configuration creating ControllerEndpointHandlerMapping. This leads to a bean conflict when autowiring RequestMappingHandlerMapping, as Spring incorrectly identifies both beans as candidates for injection. The issue specifically arises due to the order of bean creation and configuration execution, highlighting a potential problem with Spring's bean type resolution mechanism in scenarios where subtype beans are created after their base type is already in use.

Version Information

  • Spring Boot version: 3.3.0

Problem Details

  1. RequestMappingHandlerMapping is created by WebMvcConfigurationSupport.
  2. ControllerEndpointHandlerMapping (a subclass of RequestMappingHandlerMapping) is created by WebMvcEndpointManagementContextConfiguration from the actuator.
  3. When a custom configuration that depends on RequestMappingHandlerMapping runs before the configuration creating ControllerEndpointHandlerMapping, Spring is unable to distinguish between the base bean and the subtype bean.
  4. This issue is specifically tied to the order of configuration execution and bean creation.

Error Message

Parameter 0 of method workspaceConfigurationWebServiceFactory in cdq.workspaceconfiguration.starter.WorkspaceConfigurationWebServiceConfiguration required a single bean, but 2 were found:
- requestMappingHandlerMapping: defined by method 'requestMappingHandlerMapping' in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]
- controllerEndpointHandlerMapping: defined by method 'controllerEndpointHandlerMapping' in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/servlet/WebMvcEndpointManagementContextConfiguration.class]

Expected Behavior

Spring should be able to differentiate between the RequestMappingHandlerMapping bean and its subtype ControllerEndpointHandlerMapping bean, allowing the correct bean to be injected based on the required type, regardless of the order of configuration execution.

Actual Behavior

When the custom configuration runs before the configuration creating ControllerEndpointHandlerMapping, Spring detects both beans as candidates for injection, causing an ambiguity error when trying to autowire a RequestMappingHandlerMapping bean.

Workaround

Workaround I found is to load configs as primary sources so they are picked before my custom config

SpringApplication.run(new Class[]{Application.class, WebMvcAutoConfiguration.class, WebMvcEndpointManagementContextConfiguration.class}, args);

Comment From: wilkinsona

Thanks for the report. While Spring Boot has defined the two beans in question, this isn't really within its control as the dependency resolution algorithm is part of Spring Framework.

Rather than relying on ordering, which can be brittle, you may be able to clarify the intent of your configuration by making the injection point for RequestMappingHandlerMapping more precise. For example, you could match the parameter's name to that of the bean that you want to inject, or you could use @Qualifier. Alternatively, you could inject ObjectProvider<RequestMappingHandlerMapping> and then select the most appropriate match that it provides.

Beyond this, functionality that allowed an exact type match without considering any sub-classes would be a Spring Framework enhancement. You may want to request it in their issue tracker.