项目背景:A项目因为业务原因,需要B项目提供一个service的包,AB是两个独立的项目(不同数据源),A引入B项目的service包后,项目启动失败。
1.示例
我遇到的问题:
2.报错信息
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'RRExceptionHandler' for bean class [com.inspur.labor.store.core.exception.handler.RRExceptionHandler] conflicts with existing, non-compatible bean definition of same name and class [com.inspur.vista.labor.common.exception.RRExceptionHandler]
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:348)
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:286)
at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:287)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:242)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167)
... 13 common frames omitted
3.报错原因
先了解一下Spring
的beanName生成策略,AnnotationBeanNameGenerator.java
类是默认生成策略,其中生成名称的具体实现方法是buildDefaultBeanName
:
部分源码展示:
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
// ================== 部分源码 ==================
/**
* 从给定的bean定义派生一个默认的bean名称。
* <p> 这个默认名称实现的只是构建一个简短类名的去首化版本(类名首字母小写):e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
* @param 定义要为其构建bean名称的bean定义
* @return 默认的bean名称
*/
protected String buildDefaultBeanName(BeanDefinition definition) {
// 获取全限定名称
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
// 获取类名
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName); // 类名首字母小写
}
}
根据Spring
默认策略的源码可以看出,生成的类名是当前类的类名(shortClassName
),而不是类的全限定类名(beanClassName
带包名),所以不同包名下的相同类一定会发成冲突,这就是报错原因。
4.解决方案
- 自定义一个类去继承
Srping
的AnnotationBeanNameGenerator
类,并重写generateBeanName
方法返回全限定类名:
/**
* @className: CustomNameGenerator
* @description: 解决不同包下相同类名冲突
* @date: 2021/3/5 14:31
*/
public class CustomNameGenerator extends AnnotationBeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
//全限定类名
String beanName = definition.getBeanClassName();
return beanName;
}
}
- 在
Springboot
启动类上的注解@ComponentScan
中添加自定义的类名生成策略类即可生效;
@MapperScan(nameGenerator = CustomNameGenerator.class)
@ComponentScan(nameGenerator = CustomNameGenerator.class)
–如果需要转载,请注明原文出处