摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。
對配置文件解析完成后,獲取的beanDefiniton已經可以進行使用了,剩下的唯一工作就是注冊了,也就是processBeanDefinition方法中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())代碼的解析了。
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. // 使用beanName做唯一標識注冊 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. // 注冊所有的別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
從上面的代碼可以看出,解析的beanDefinition都會被注冊到BeanDefinitionRegistry類型的實例中,而對於beanDefinition的注冊分成了兩部分:通過beanName的注冊以及通過別名的注冊。
1. 通過beanName注冊BeanDefinition
對於beanDefinition的注冊,是將beanDefinition直接放入了map中,以beanName為key。但不僅僅如此,代碼如下:
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { /** * 注冊前的最后一次校驗,這里的校驗不同於之前的XML文件校驗, * 主要是對於AbstractBeanDefinition屬性中的methodOverrides校驗, * 校驗methodOverrides是否與工廠方法並存或者methodOverrides對應的方法根本不存在 */ ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); // 處理注冊已經注冊的beanName情況 if (existingDefinition != null) { // 如果對應的beanName已經注冊且在配置中配置了bean不允許被覆蓋,則拋出異常。 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) // 因為beanDefinitionMap是全局變量,這里定會存在並發訪問的情況 synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase // 注冊beanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); // 記錄beanName this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { // 重置所有beanName對應的緩存 resetBeanDefinition(beanName); } }
上面的代碼中我們看到,在對於bean的注冊處理方式上,主要進行了幾個步驟:
(1) 對AbstractBeanDefinition的校驗。在解析XML文件的時候我們提過校驗,但是此校驗非彼校驗,之前的校驗是針對XML格式的校驗,而此時的校驗是針對AbstractBeanDefinition的methodOverrides屬性的。
(2)對beanName已經注冊的情況的處理。如果設置了不允許bean的覆蓋,則需要拋出異常,否則直接覆蓋。
(3)加入map緩存。
(4)清楚解析之前留下的對應beanName的緩存。
2. 通過別名注冊BeanDefinition
在理解了注冊bean的原理后,理解注冊別名的原理就容易多了。
@Override public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { // 如果beanName與alias相同的話不記錄alias,並刪除對應的alias if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { // 如果alias不允許被覆蓋則拋出異常 String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } // 當A -> B存在時,若再次出現 A -> C -> B時候則會拋出異常 checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
由以上代碼中可以得知注冊alias的步驟如下:
(1)beanName與alias相同情況處理。若alias和beanName名稱相同則不需要處理並刪除原有的alias。
(2)alias覆蓋處理。若aliasName已經使用並已經指向了另一beanName則需要用戶的設置進行處理。
(3)alias循環檢查。當A -> B存在時,若再次出現 A -> C -> B時候則會拋出異常。
(4)注冊alias。
