项目背景:
两个项目的包结构和类名都很多相同,于是开始考虑使用加一级包进行隔离,类似于这种结构
但是在启动的过程中,抛出来这样的异常:
1 2 3 4 5 6 7 8 9 | Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'nameConflict' for bean class [xom.liuyun.beannameconflict.modelB.NameConflict] conflicts with existing, non-compatible bean definition of same name and class [xom.liuyun.beannameconflict.modelA.NameConflict] at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java: 348 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java: 286 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java: 132 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java: 284 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java: 241 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java: 198 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java: 166 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE] ... 13 common frames omitted。 |
原因:
spring提供两种beanName生成策略,基于注解的sprong-boot默认使用的是AnnotationBeanNameGenerator,它生成beanName的策略就是,取当前类名(不是全限定类名)作为beanName。由此,如果出现不同包结构下同样的类名称,肯定会出现冲突。
解决方案如下:
1. 自己写一个类实现 org.springframework.beans.factory.support.BeanNameGeneraot接口
public class UniqueNameGenerator extends AnnotationBeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
//全限定类名
String beanName = definition.getBeanClassName();
return beanName;
}
}
2. 在启动类上加注解@ComponentScan(nameGenerator = UniqueNameGenerator.class)使刚才我们自定义的BeanName生成策略生效。
@SpringBootApplication
@ComponentScan(nameGenerator = UniqueNameGenerator.class)
public class BeanNameConflictApplication {
public static void main(String[] args) {
SpringApplication.run(BeanNameConflictApplication.class, args);
}
}
这样,问题就可以解决了。
另外解决方式:
解决办法,一:将其中一个实现类改为不同的名字;
二:将其中一个注解变更为一个name为非roleServiceImpl的注解@service(name="aaaa")。
别名
@Autowired
注解时,属性名即为默认的Bean名,如下面的logPrint
就是获取beanName=logPrint
的bean@Resource(name=xxx)
直接指定Bean的name,来唯一选择匹配的bean
说明:
@Primary
注解
这个注解就是为了解决当有多个bean满足注入条件时,有这个注解的实例被选中
@Resource 指定beanName的是否会被@Primary影响
前面的@Autowired注解 + 属性名的方式,是按照第一节的方式选择呢,还是选择被@Primary标识的实例
@Autowired + 随意的一个非beanName的属性,验证是否会选中@Primary标识的注解
根据前面的执行,因此可以知晓,选择bean的方式如下
存在@Primary注解时
@Resource注解指定name时,根据name来查找对应的bean
@Autowired注解,全部都用@Primary标识的注解
@Primary注解要求唯一(非广义的唯一性,并不是指只能用一个@Primary,具体看前面)
不存在@Primary注解时
@Resource注解指定name时,根据name来查找对应的bean
@Autowired注解时,根据属性名去查对应的Bean,如果查不到则抛异常;如果查到,那即是它了
spring-projects/spring-boot: 是一个用于简化Spring应用开发的框架。适合用于需要快速开发企业级Java应用的项目。特点是可以提供自动配置、独立运行和内置的Tomcat服务器,简化Spring应用的构建和部署。
最近提交(Master分支:6 天前 )
d3a2bf40
* pr/42289:
Add common definition annotations support for ConfigurationProperties
Closes gh-42289
2 天前
44be2e11
Update `` to ensure that common bean definition annotations, such as
`@Lazy`, `@Primary` and `@Fallback`, are applied.
See gh-42289
2 天前
所有评论(0)