当前位置 : 主页 > 编程语言 > java >

Spring5 IOC容器解析——BeanDefinition的注册

来源:互联网 收集:自由互联 发布时间:2023-02-04
前言 在上一篇文章解析BeanDefinition对配置文件解析完成后,获取的beanDefiniton已经可以进行使用了,剩下的唯一工作就是注册了,也就是processBeanDefinition方法中的BeanDefinitionReaderUtils.reg

前言

在上一篇文章解析BeanDefinition 对配置文件解析完成后,获取的beanDefiniton已经可以进行使用了,剩下的唯一工作就是注册了,也就是processBeanDefinition方法中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())代码的解析了。

BeanDefinitionRegistry

该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程。 它的接口定义如下:

public interface BeanDefinitionRegistry extends AliasRegistry { /** * 往注册表中注册一个新的 BeanDefinition 实例 * Register a new bean definition with this registry. * Must support RootBeanDefinition and ChildBeanDefinition. * @param beanName the name of the bean instance to register * @param beanDefinition definition of the bean instance to register * @throws BeanDefinitionStoreException if the BeanDefinition is invalid * @throws BeanDefinitionOverrideException if there is already a BeanDefinition * for the specified bean name and we are not allowed to override it * @see GenericBeanDefinition * @see RootBeanDefinition * @see ChildBeanDefinition */ void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; /** * 移除注册表中已注册的 BeanDefinition 实例 * Remove the BeanDefinition for the given name. * @param beanName the name of the bean instance to register * @throws NoSuchBeanDefinitionException if there is no such bean definition */ void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; /** * 从注册中取得指定的 BeanDefinition 实例 * Return the BeanDefinition for the given bean name. * @param beanName name of the bean to find a definition for * @return the BeanDefinition for the given name (never {@code null}) * @throws NoSuchBeanDefinitionException if there is no such bean definition */ BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; /** * 判断 BeanDefinition 实例是否在注册表中(是否注册) * Check if this registry contains a bean definition with the given name. * @param beanName the name of the bean to look for * @return if this registry contains a bean definition with the given name */ boolean containsBeanDefinition(String beanName); /** * 取得注册表中所有 BeanDefinition 实例的 beanName(标识) * Return the names of all beans defined in this registry. * @return the names of all beans defined in this registry, * or an empty array if none defined */ String[] getBeanDefinitionNames(); /** * 返回注册表中 BeanDefinition 实例的数量 * Return the number of beans defined in the registry. * @return the number of beans defined in the registry */ int getBeanDefinitionCount(); /** * beanName(标识)是否被占用 * Determine whether the given bean name is already in use within this registry, * i.e. whether there is a local bean or alias registered under this name. * @param beanName the name to check * @return whether the given bean name is already in use */ boolean isBeanNameInUse(String beanName); }

再来看BeanDefinitionRegistry的继承关系,DefaultListableBeanFactory赫然在列:

DefaultListableBeanFactory

该类是 BeanDefinitionRegistry 接口的基本实现类,但同时也实现其他了接口的功能,这里只探究下其关于注册 BeanDefinition 实例的相关方法 。

 

首先来看它的成员变量:

// 关键-> 注册表,由 BeanDefinition 的标识 (beanName) 与其实例组成 /** Map of bean definition objects, keyed by bean name. */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 标识(beanName)集合 /** List of bean definition names, in registration order. */ private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

现在进入DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法

/** * Process the given bean element, parsing the bean definition * and registering it with the registry. * 解析BeanDefinition资源 */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类 //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向Spring IOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. // 在完成BeanDefinition注册之后,往容器发送注册完成的事件 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }

再来看 BeanDefinitionReaderUtils 的 registerBeanDefinition 方法。该方法的主要作用是调用注册器(DefaultListableBeanFactory)完成注册过程。

/** * 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。但不仅仅如此,代码如下:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { /** Resolver to use for checking if a bean definition is an autowire candidate. */ private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver(); /** Map from dependency type to corresponding autowired value. */ private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16); // 关键-> 注册表,由 BeanDefinition 的标识 (beanName) 与其实例组成 /** Map of bean definition objects, keyed by bean name. */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); /** Map from bean name to merged BeanDefinitionHolder. */ private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256); /** Map of singleton and non-singleton bean names, keyed by dependency type. */ private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64); /** Map of singleton-only bean names, keyed by dependency type. */ private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64); // 标识(beanName)集合 /** List of bean definition names, in registration order. */ private volatile List<String> beanDefinitionNames = new ArrayList<>(256); /** List of names of manually registered singletons, in registration order. */ private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16); /** Cached array of bean definition names in case of frozen configuration. */ @Nullable private volatile String[] frozenBeanDefinitionNames; /** Whether bean definition metadata may be cached for all beans. */ private volatile boolean configurationFrozen = false; @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { // 校验 beanName 与 beanDefinition 非空 Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); /** * 1、校验 BeanDefinition * 注册前的最后一次校验,这里的校验不同于之前的XML文件校验, * 主要是对于AbstractBeanDefinition属性中的lookup-method属性和replaced-method属性对应的重写方法是否存在并且合法, * 校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在 */ if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } // 2、从缓存中获取指定 beanName 的 BeanDefinition BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); //3、看看beanName是否已经存在容器里,存在则表明已经被注册过 if (existingDefinition != null) { // 如果存在但是不允许覆盖,抛出异常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } // 覆盖 beanDefinition 大于 被覆盖的 beanDefinition 的 ROLE ,打印 info 日志 else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志 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 { // 其它,打印 debug 日志 if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } // 允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinit 大专栏 注册BeanDefinitions-下ionMap 中。 this.beanDefinitionMap.put(beanName, beanDefinition); } //4、如果未存在 else { // 检测创建 Bean 阶段是否已经开启,如果开启了则需要对 beanDefinitionMap 进行并发控制 if (hasBeanCreationStarted()) { // beanDefinitionMap 为全局变量,避免并发情况 // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { // 添加BeanDefinition 到 beanDefinitionMap 中。 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 从 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } } else { // Still in startup registration phase // 添加 BeanDefinition 到 beanDefinitionMap 中。 this.beanDefinitionMap.put(beanName, beanDefinition); // 添加 beanName 到 beanDefinitionNames 中 this.beanDefinitionNames.add(beanName); // 从 manualSingletonNames 移除 beanName removeManualSingletonName(beanName); } //将注册期间被冻结的BeanDefinition的名字列表清除掉 this.frozenBeanDefinitionNames = null; } // 5、重新设置 beanName 对应的缓存 //检查是否有同名的BeanDefinition已经在IOC容器中注册 if (existingDefinition != null || containsSingleton(beanName)) { //尝试重置所有已经注册过的BeanDefinition的缓存,包括BeanDefinition //的父类以及合并的beanDefinition的缓存,所谓的合并BeanDefinition //指的的有parent属性的beandefinition,该BeanDefinition会把parent的 //BeanDefinition属性合并在一块 resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } } }

上面的代码中我们看到,在对于bean的注册处理方式上,主要进行了几个步骤:

  • 1、对AbstractBeanDefinition的校验。在解析XML文件的时候我们提过校验,但是此校验非彼校验,之前的校验是针对XML格式的校验,而此时的校验是针对AbstractBeanDefinition的methodOverrides属性的。
  • 2、对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
  • 3、加入map缓存。
  • 4、清楚解析之前留下的对应beanName的缓存。

2、通过别名注册BeanDefinition

在理解了注册bean的原理后,理解注册别名的原理就容易多了。

先看别名注册接口AliasRegistry

public interface AliasRegistry { /** * 注册表中给name注册一个别名alias * Given a name, register an alias for it. * @param name the canonical name * @param alias the alias to be registered * @throws IllegalStateException if the alias is already in use * and may not be overridden */ void registerAlias(String name, String alias); /** * 移除注册表中的别名alias * Remove the specified alias from this registry. * @param alias the alias to remove * @throws IllegalStateException if no such alias was found */ void removeAlias(String alias); /** * 校验注册表中是否存在别名name * Determine whether the given name is defined as an alias * (as opposed to the name of an actually registered component). * @param name the name to check * @return whether the given name is an alias */ boolean isAlias(String name); /** * 在注册表中获取给定那么的所有别名信息 * Return the aliases for the given name, if defined. * @param name the name to check for aliases * @return the aliases, or an empty array if none */ String[] getAliases(String name); }

接着跟进registry.registerAlias(beanName, alias)

public class SimpleAliasRegistry implements AliasRegistry { //别名-规范名称的映射MAP,用于存储注册信息(内存注册表) /** Map from alias to canonical name. */ private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16); //注册表中注册别名 @Override public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); //锁注册表 //因为CurrentHashMap只有put和remove是线程安全的 //此处要包装对CurrentHashMap的复合操作线程安全 synchronized (this.aliasMap) { // 如果beanName与alias相同的话不记录alias,并删除对应的alias if (alias.equals(name)) { //如果别名与名字相同,则在Map中移除 this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { //获取当前别名在注册表中的规范名称 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 + "'"); } } // // 校验规范名称是否指向当前别名的 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。

SimpleAliasRegistry的其他方法

public class SimpleAliasRegistry implements AliasRegistry { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); //别名-规范名称的映射MAP,用于存储注册信息(内存注册表) /** Map from alias to canonical name. */ private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16); //注册表中注册别名 @Override public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); //锁注册表 //因为CurrentHashMap只有put和remove是线程安全的 //此处要包装对CurrentHashMap的复合操作线程安全 synchronized (this.aliasMap) { // 如果beanName与alias相同的话不记录alias,并删除对应的alias if (alias.equals(name)) { //如果别名与名字相同,则在Map中移除 this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { //获取当前别名在注册表中的规范名称 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 + "'"); } } // // 校验规范名称是否指向当前别名的 checkForAliasCircle(name, alias); // 注册表注册别名与规范名称的映射 this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } } /** * 是否允许重写注册表别名信息,默认true * Determine whether alias overriding is allowed. * <p>Default is {@code true}. */ protected boolean allowAliasOverriding() { return true; } /** * 校验给定的name-alias映射是否已在注册表aliasMap中 * Determine whether the given name has the given alias registered. * @param name the name to check * @param alias the alias to look for * @since 4.2.1 */ public boolean hasAlias(String name, String alias) { //获取注册表中单映射的规范名称name String registeredName = this.aliasMap.get(alias); return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null && hasAlias(name, registeredName)); } /** * 移除别名,在注册表aliasMap中 * @param alias the alias to remove */ @Override public void removeAlias(String alias) { synchronized (this.aliasMap) { String name = this.aliasMap.remove(alias); if (name == null) { throw new IllegalStateException("No alias '" + alias + "' registered"); } } } //校验是否包含给定的别名,在注册表中 @Override public boolean isAlias(String name) { return this.aliasMap.containsKey(name); } // 在注册表获取给定规范名称的所有别名信息 @Override public String[] getAliases(String name) { List<String> result = new ArrayList<>(); synchronized (this.aliasMap) { retrieveAliases(name, result); } return StringUtils.toStringArray(result); } /** * Transitively retrieve all aliases for the given name. * @param name the target name to find aliases for * @param result the resulting aliases list */ private void retrieveAliases(String name, List<String> result) { this.aliasMap.forEach((alias, registeredName) -> { //判断当前别名的规范名称是否为要查询的 if (registeredName.equals(name)) { result.add(alias); //递归查询循环引用的别名 retrieveAliases(alias, result); } }); } /** * Resolve all alias target names and aliases registered in this * registry, applying the given {@link StringValueResolver} to them. * <p>The value resolver may for example resolve placeholders * in target bean names and even in alias names. * @param valueResolver the StringValueResolver to apply */ public void resolveAliases(StringValueResolver valueResolver) { Assert.notNull(valueResolver, "StringValueResolver must not be null"); synchronized (this.aliasMap) { Map<String, String> aliasCopy = new HashMap<>(this.aliasMap); aliasCopy.forEach((alias, registeredName) -> { String resolvedAlias = valueResolver.resolveStringValue(alias); String resolvedName = valueResolver.resolveStringValue(registeredName); if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) { this.aliasMap.remove(alias); } else if (!resolvedAlias.equals(alias)) { String existingName = this.aliasMap.get(resolvedAlias); if (existingName != null) { if (existingName.equals(resolvedName)) { // Pointing to existing alias - just remove placeholder this.aliasMap.remove(alias); return; } throw new IllegalStateException( "Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias + "') for name '" + resolvedName + "': It is already registered for name '" + registeredName + "'."); } checkForAliasCircle(resolvedName, resolvedAlias); this.aliasMap.remove(alias); this.aliasMap.put(resolvedAlias, resolvedName); } else if (!registeredName.equals(resolvedName)) { this.aliasMap.put(alias, resolvedName); } }); } } /** * 校验给定的名称是否指向别名,不指向异常抛出 * Check whether the given name points back to the given alias as an alias * in the other direction already, catching a circular reference upfront * and throwing a corresponding IllegalStateException. * @param name the candidate name * @param alias the candidate alias * @see #registerAlias * @see #hasAlias */ protected void checkForAliasCircle(String name, String alias) { if (hasAlias(alias, name)) { throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': Circular reference - '" + name + "' is a direct or indirect alias for '" + alias + "' already"); } } /** * 根据给定的别名获取规范名称 * Determine the raw name, resolving aliases to canonical names. * @param name the user-specified name * @return the transformed name */ public String canonicalName(String name) { String canonicalName = name; // Handle aliasing... String resolvedName; do { //获取给定别名的规范名称,获取到跳出循环 resolvedName = this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while (resolvedName != null); return canonicalName; } }

SimpleBeanDefinitionRegistry 为BeanDefinitionRegistry的默认实现,同时继承AliasRegistry的默认实现SimpleAliasRegistry,所以它总共维护了两个注册表aliasMap(别名注册表)与beanDefinitionMap(bean描述注册表),到此AliasRegistry接口功能的主要实现以及扩展接口的主要实现通过源码已清晰展示

 

参考: https://www.cnblogs.com/monkey0307/p/8509701.html

https://www.cnblogs.com/warehouse/p/9380473.html

https://www.cnblogs.com/moxiaotao/p/9349549.html

https://www.cnblogs.com/loongk/p/12297193.html

https://blog.csdn.net/whoyou223/article/details/78205803

网友评论