项目背景:
两个项目的包结构和类名都很多相同,于是开始考虑使用加一级包进行隔离,类似于这种结构
但是在启动的过程中,抛出来这样的异常:
1 2 3 4 5 6 7 8 9 |
|
原因:
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,如果查不到则抛异常;如果查到,那即是它了