【Spring】重復的beanName覆蓋原則(九)


  在Spring中,可以有由於存在重復的beanName會有一些問題

  下面看看,Spring是怎么處理重復的beanName的

1、Spring容器內置了 ConfigurationClassPostProcessor 配置類工廠bean后置處理器,在Bean工廠准備好后,調用 postProcessBeanDefinitionRegistry() 方法來后置處理bean工廠

 1 @Override
 2 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
 3     int registryId = System.identityHashCode(registry);
 4     if (this.registriesPostProcessed.contains(registryId)) {
 5         throw new IllegalStateException(
 6                 "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
 7     }
 8     if (this.factoriesPostProcessed.contains(registryId)) {
 9         throw new IllegalStateException(
10                 "postProcessBeanFactory already called on this post-processor against " + registry);
11     }
12     // 給后置處理器,添加注冊ID
13     this.registriesPostProcessed.add(registryId);
14     // 解析配置的bean定義
15     processConfigBeanDefinitions(registry);
16 }

2、processConfigBeanDefinitions() 處理配置bean定義

 1 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 2     
 3     ......
 4 
 5     // Parse each @Configuration class
 6     // 創建一個配置類解析器對象
 7     ConfigurationClassParser parser = new ConfigurationClassParser(
 8             this.metadataReaderFactory, this.problemReporter, this.environment,
 9             this.resourceLoader, this.componentScanBeanNameGenerator, registry);
10 
11     // 創建一個集合用於保存配置類BeanDefinitionHolder集合默認長度是配置類集合的長度
12     Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
13     // 創建一個集合用於保存已經解析的配置類,長度默認為解析出來默認的配置類的集合長度
14     Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
15     //do while 會進行第一次解析
16     do {
17         // 使用配置類解析器,解析配置類
18         parser.parse(candidates);
19         // 使用配置類解析器,驗證
20         parser.validate();
21         // 解析出來的配置類,即從解析器的配置類屬性中獲取解析出來的配置類
22         Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
23         configClasses.removeAll(alreadyParsed);
24 
25         // Read the model and create bean definitions based on its content
26         if (this.reader == null) {
27             this.reader = new ConfigurationClassBeanDefinitionReader(
28                     registry, this.sourceExtractor, this.resourceLoader, this.environment,
29                     this.importBeanNameGenerator, parser.getImportRegistry());
30         }
31         // 真正的把解析出來的配置類注冊到容器中
32         this.reader.loadBeanDefinitions(configClasses);
33 
34         ....
35     }
36     // 存在沒有解析過的 需要循環解析
37     while (!candidates.isEmpty());
38 
39     .....
40 }

3、解析出來后,通過 loadBeanDefinitions() 方法,把bean定義注冊到容器中

  loadBeanDefinitions() -> loadBeanDefinitionsForConfigurationClass() -> loadBeanDefinitionsForBeanMethod()

  加載被@Bean修飾的方法 bean定義時

 1 // 從Bean方法中加載Bean定義
 2 private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
 3     
 4     ......
 5 
 6     // Has this effectively been overridden before (e.g. via XML)?
 7     // 是否覆蓋已經存在的Bean定義
 8     /**
 9      * 0、不存在相同Bean定義名稱的,則返回false。繼續添加bean定義
10      * 1、配置類的名字相同,則報錯
11      * 2、同一個配置類中的@Bean名字相同,則返回true,意思是以先加載的@Bean方法為准
12      * 3、不同的配置類中的@Bean名字相同,則返回false,意思是可以被覆蓋,已后被加載的@Bean方法為准
13      */
14     if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
15         // 配置類名稱相同報異常
16         if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
17             throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
18                     beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
19                     "' clashes with bean name for containing configuration class; please make those names unique!");
20         }
21         return;
22     }
23 
24     // 創建配置類的Bean定義
25     ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
26 
27     ......
28 
29     // 注冊Bean定義
30     this.registry.registerBeanDefinition(beanName, beanDefToRegister);
31 }

4、isOverriddenByExistingDefinition() 判斷是否覆蓋已經存在的Bean定義的方法

 1 // 是否覆蓋已經存在的Bean定義
 2 protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
 3     if (!this.registry.containsBeanDefinition(beanName)) {
 4         return false;
 5     }
 6     BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
 7 
 8     // 存在的Bean定義 是否是 配置類Bean定義類型
 9     if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
10         ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
11         // 是否是同一個配置類名
12         if (ccbd.getMetadata().getClassName().equals(
13                 beanMethod.getConfigurationClass().getMetadata().getClassName())) {
14             if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
15                 ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());
16             }
17             return true;
18         }
19         else {
20             return false;
21         }
22     }
23 
24     // 屬性掃描生成的Bean定義
25     if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
26         return false;
27     }
28 
29     // 現有的bean定義bean是否標記為框架生成的bean
30     if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
31         return false;
32     }
33 
34     
35     if (this.registry instanceof DefaultListableBeanFactory &&
36             !((DefaultListableBeanFactory) this.registry).isAllowBeanDefinitionOverriding()) {
37         throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
38                 beanName, "@Bean definition illegally overridden by existing bean definition: " + existingBeanDef);
39     }
40     if (logger.isDebugEnabled()) {
41         logger.debug(String.format("Skipping bean definition for %s: a definition for bean '%s' " +
42                 "already exists. This top-level bean definition is considered as an override.",
43                 beanMethod, beanName));
44     }
45     return true;
46 }

5、注冊bean定義方法 registerBeanDefinition()

 1 // 在Bean工廠中注冊bean定義
 2 @Override
 3 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
 4         throws BeanDefinitionStoreException {
 5 
 6     Assert.hasText(beanName, "Bean name must not be empty");
 7     Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 8 
 9     // 判斷bean定義 屬於抽象的bean定義
10     if (beanDefinition instanceof AbstractBeanDefinition) {
11         try {
12             // 驗證bean定義
13             ((AbstractBeanDefinition) beanDefinition).validate();
14         }
15         catch (BeanDefinitionValidationException ex) {
16             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
17                     "Validation of bean definition failed", ex);
18         }
19     }
20 
21     // 根據bean名字獲取已經存在的bean定義
22     BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
23     if (existingDefinition != null) {
24         // 是否允許覆蓋Bean定義  allowBeanDefinitionOverriding默認值為true
25         if (!isAllowBeanDefinitionOverriding()) {
26             throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
27         }
28         else if (existingDefinition.getRole() < beanDefinition.getRole()) {
29             // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
30             if (logger.isInfoEnabled()) {
31                 logger.info("Overriding user-defined bean definition for bean '" + beanName +
32                         "' with a framework-generated bean definition: replacing [" +
33                         existingDefinition + "] with [" + beanDefinition + "]");
34             }
35         }
36         else if (!beanDefinition.equals(existingDefinition)) {
37             if (logger.isDebugEnabled()) {
38                 logger.debug("Overriding bean definition for bean '" + beanName +
39                         "' with a different definition: replacing [" + existingDefinition +
40                         "] with [" + beanDefinition + "]");
41             }
42         }
43         else {
44             if (logger.isTraceEnabled()) {
45                 logger.trace("Overriding bean definition for bean '" + beanName +
46                         "' with an equivalent definition: replacing [" + existingDefinition +
47                         "] with [" + beanDefinition + "]");
48             }
49         }
50         this.beanDefinitionMap.put(beanName, beanDefinition);
51     }
52     else {
53         // 判斷Bean工廠是否已經開始創建Bean了
54         if (hasBeanCreationStarted()) {
55             // Cannot modify startup-time collection elements anymore (for stable iteration)
56             synchronized (this.beanDefinitionMap) {
57                 this.beanDefinitionMap.put(beanName, beanDefinition);
58                 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
59                 updatedDefinitions.addAll(this.beanDefinitionNames);
60                 updatedDefinitions.add(beanName);
61                 this.beanDefinitionNames = updatedDefinitions;
62                 removeManualSingletonName(beanName);
63             }
64         }
65         else {
66             
67             // 放入到bean工廠的bean定義的Map集合中
68             this.beanDefinitionMap.put(beanName, beanDefinition);
69             // 添加beanName 到 名稱集合中
70             this.beanDefinitionNames.add(beanName);
71             // 刪除手動單例名稱
72             removeManualSingletonName(beanName);
73         }
74         this.frozenBeanDefinitionNames = null;
75     }
76 
77     if (existingDefinition != null || containsSingleton(beanName)) {
78         // 重置Bean定義
79         resetBeanDefinition(beanName);
80     }
81 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM