I did small sample project to show behavior which we are getting on bigger project. We are using actuator endpoints and same time we have a service where we are autowiring RequestMappingHandlerMapping. Our code was working in spring boot 2.6.x, but in version 2.7.x (even in latest 2.7.2) it is not working. When actuator is not put as dependency then this autowiring works, but in our case application will not start and we are getting this error:
Parameter 0 of constructor in com.example.demo.VersionInfoService 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]
sample application for reproducing build.gradle
plugins {
id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
VersionInfoService.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Service
public class VersionInfoService {
RequestMappingHandlerMapping handlerMapping;
@Autowired
public VersionInfoService(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
}
Demo1Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
Comment From: wilkinsona
The difference in behavior between 2.6 and 2.7 is due to the changes made for https://github.com/spring-projects/spring-boot/issues/29682.
Comment From: wilkinsona
Thanks for the sample, @turja12. It made is much easier to determine the cause of the change in behavior.
I've updated the release notes for 2.7 with a section on requestMappingHandlerMapping no longer being @Primary. In the case of your sample, the problem can be fixed by changing the constructor of VersionInfoService:
public VersionInfoService(@Qualifier("requestMappingHandlerMapping") RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
Comment From: dreis2211
Or alternatively handling just multiple beans of that type - that's what we ended up doing. E.g.
@Service
public class VersionInfoService {
List<RequestMappingHandlerMapping> handlerMappings;
public VersionInfoService(List<RequestMappingHandlerMapping> handlerMappings) {
this.handlerMappings = handlerMappings;
}
}
Plus whatever changes are needed that call the handlerMapping. In our case these were relatively straight-forward - we're just looking in a list of mappings instead of a single one now.
Comment From: wilkinsona
Good point, @dreis2211. Thanks. I've added that as an option to the release notes as well.
Comment From: turja12
Thanks for clarification, solution and extending release notes.
Comment From: alexisbedoya
Hello, something similar happens to me but with the reactive module, I use webclient and the project is based on webflux, it is an ohs and the list of integrations is quite extensive, there is the possibility of creating the bean for No qualifying bean of type 'org.springframework .web.reactive.result.method.annotation.RequestMappingHandlerMapping' available: expected single matching bean but found 2: controllerEndpointHandlerMapping,requestMappingHandlerMapping