1. 程式人生 > >spring-boot不同包結構下,同名類衝突導致服務啟動失敗解決方案

spring-boot不同包結構下,同名類衝突導致服務啟動失敗解決方案

專案背景:

  兩個專案的包結構和類名都很多相同,於是開始考慮使用加一級包進行隔離,類似於這種結構

但是在啟動的過程中,丟擲來這樣的異常:

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,如果查不到則拋異常;如果查到,那即是它了