标签:doc multi lte cte qualifier check nes deb rop
出现问题的项目算是一个新项目,但基本的脚手架代码是从另一个项目里迁过来的,原项目并没有报错,只有新项目才报异常。看报错内容,判断发生冲突的主要是spring-boot-starter-security和springfox-swagger2这两个jar包的文件。
新项目错误如下:
Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug‘ enabled.
15:22:32.350 spotcheck-system [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a single bean, but 2 were found:
- requestMappingHandlerMapping: defined by method ‘requestMappingHandlerMapping‘ in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]
- swagger2ControllerMapping: defined by method ‘swagger2ControllerMapping‘ in class path resource [springfox/documentation/swagger2/configuration/Swagger2DocumentationConfiguration.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘springSecurityFilterChain‘ defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method ‘springSecurityFilterChain‘ threw exception; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping‘ available: expected single matching bean but found 2: requestMappingHandlerMapping,swagger2ControllerMapping
我的项目中出错代码是这一行,在原项目并没有报错。
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
getBean方法默认是byType来加载bean对象的,如果取到相同类型的2个就会报错。我分别查看了错误中提示的DelegatingWebMvcConfiguration.class和Swagger2DocumentationConfiguration.class。
1. DelegatingWebMvcConfiguration.class里并没有requestMappingHandlerMapping方法,DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport.class类,在WebMvcConfigurationSupport.class类中有requestMappingHandlerMapping方法,返回值是RequestMappingHandlerMapping.class。代码如下:
/** * Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping * requests to annotated controllers. */ @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); ...... }
2. Swagger2DocumentationConfiguration.class里有swagger2ControllerMapping方法如下:
@Bean
public HandlerMapping swagger2ControllerMapping(
Environment environment,
DocumentationCache documentationCache,
ServiceModelToSwagger2Mapper mapper,
JsonSerializer jsonSerializer) {
return new PropertySourcedRequestMappingHandlerMapping(environment, new Swagger2Controller(environment, documentationCache, mapper, jsonSerializer));
}
这个方法里的返回值类型PropertySourcedRequestMappingHandlerMapping继承了RequestMappingHandlerMapping类,
public class PropertySourcedRequestMappingHandlerMapping extends RequestMappingHandlerMapping { ...... }
所以可能Spring加载时,根据byType形式会认错了吧。
解决办法:既然Spring加载时使用byType形式会报错,那我们就用byName形式加载。Spring中使用@Bean声明的方法,如果没有指定名称,默认的name就是方法名。所以我们把出错代码改成:
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
到此问题解决。
补充一下:
假设自己项目中有一个接口,同时有两个实现类,并且实现类都使用了@Service注解,你在使用过程中使用了@Autowired注解进行引用。这时Spring初始化时就会报错:expected single matching bean but found 2 ,因为@Autowired默认是byType形式加载的。
解决办法就是用@Primary、@Qualifier这两个注解来解决问题。
@Primary注解是用来声明2个实现类那个是主要的。与@Component、@Service等注解放到一起使用。这时Spring通过@Autowired加载时,就会判断一下, 优先使用@Primary注解的类。
@Qualifier显示声明加载类的名称,与@Autowired放到一起使用,这样Spring加载时判断类型相同,会在通过名称筛选出需要的类,就不会报错了。其实@Autowired + @Qualifier = @Resource,如果真需要byName形式加载,直接使用@Resource就可以了。
标签:doc multi lte cte qualifier check nes deb rop
原文地址:https://www.cnblogs.com/huanshilang/p/13093712.html