项目背景: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.解决方案

  1. 自定义一个类去继承SrpingAnnotationBeanNameGenerator类,并重写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;
    }
}
  1. Springboot启动类上的注解@ComponentScan中添加自定义的类名生成策略类即可生效;
@MapperScan(nameGenerator = CustomNameGenerator.class)
@ComponentScan(nameGenerator = CustomNameGenerator.class)

–如果需要转载,请注明原文出处

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐