在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