spring-boot不同包結構下,同名類衝突導致服務啟動失敗解決方案
專案背景:
兩個專案的包結構和類名都很多相同,於是開始考慮使用加一級包進行隔離,類似於這種結構
但是在啟動的過程中,丟擲來這樣的異常:
1 2 3 4 5 6 7 8 9 |
class [xom.liuyun.beannameconflict.modelA.NameConflict]
286 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE]
284 ) ~[spring-context- 5.0 . 4 .RELEASE.jar: 5.0 . 4 .RELEASE]
|
原因:
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,如果查不到則拋異常;如果查到,那即是它了