3.2-3、Spring源码学习:DefaultBeanDefinitionDocumentReader.parseDefaultElement(:解析默认标签

文章目录

      • 前言
      • 承上启下
      • 进入源码:DefaultBeanDefinitionDocumentReader.parseDefaultElement(
      • import标签
        • AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources)
      • beans标签
      • alias标签
        • SimpleAliasRegistry.registerAlias(
      • 真正对bean解析的只有 bean标签
      • DefaultBeanDefinitionDocumentReader.processBeanDefinition(:bean标签的处理
        • BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele):将 bean 标签解析为 BeanDefinitionHolder
          • BeanDefinitionHolder:bean定义信息和名称、别名
            • BeanDefinition:Spring bean的定义信息:如scope、lazy-init
          • BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)
            • 默bean 标签生成beanName的逻辑:类全限定名#数字
        • BeanDefinitionReaderUtils.registerBeanDefinition(:注册每一个bean相关信息:scope、注入方式、alias等
          • DefaultListableBeanFactory.registerBeanDefinition(:检查同名bean的覆盖操作就在这里哟
            • AbstractBeanFactory.hasBeanCreationStarted()

前言

体能状态先于精神状态,习惯先于决心,聚焦先于喜好。

承上启下

在上一篇文章中Spring源码学习:reader.loadBeanDefinitions(configLocation);,我们看到源码对于 配置文件的加载过程最后落脚点是区分默认标签和用户自定义标签,而对于默认标签,就是 对xml配置文件中 import、alias、bean、beans 标签的解读,限于篇幅将对这四个标签的解读单独拿了出来,也就是本文要呈现的内容。

  • 阅读完源码我们可以了解到,import 用于引用新的配置文件,beans 用于包含不同的profile,alias用于给bean起别名,bean才是真正的Spring bean的注册。这一部分我们在上一次的图形基础上增加了蓝色线的部分。

3.2-3、Spring源码学习:DefaultBeanDefinitionDocumentReader.parseDefaultElement(:解析默认标签_第1张图片

进入源码:DefaultBeanDefinitionDocumentReader.parseDefaultElement(

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果标签时 import
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//如果标签时 alias
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//如果标签时 bean
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//如果便签是 beans
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

import标签

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(
用于解析 import 标签,从给定的 resource 中加载 bean definitions 到 bean factory 中。
可以看到import可以包含 全局变量、绝对地址、相对地址,当解析为具体地址后,具体解析委托给了 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources) 方法,而这个方法内部则是调用我们之前分析的方法 Spring源码学习:reader.loadBeanDefinitions(configLocation);

	protected void importBeanDefinitionResource(Element ele) {
		String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
		if (!StringUtils.hasText(location)) {
			getReaderContext().error("Resource location must not be empty", ele);
			return;
		}

		// 解析系统配置,即允许使用 ${user.dir} 来指定location的值,当然也可以写死
		location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

		Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

		// 判断 location 是绝对还是相对 URI
		boolean absoluteLocation = false;
		try {
			absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
		}
		catch (URISyntaxException ex) {
			// cannot convert to an URI, considering the location relative
			// unless it is the well-known Spring prefix "classpath*:"
		}

		// 如果 location 是绝对 uri
		if (absoluteLocation) {
			try {
			    // 将地址传入进行具体解析
				int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
				if (logger.isDebugEnabled()) {
					logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
				}
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error(
						"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
			}
		}
		else {
			// 不是绝对地址,则需要按照相对当前文件的地址来解析文件
			try {
				int importCount;
				//获取相对地址资源
				Resource relativeResource = getReaderContext().getResource().createRelative(location);
				//如果相对地址获取到资源
				if (relativeResource.exists()) {
					// 将地址传入进行具体解析
					importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
					actualResources.add(relativeResource);
				}
				else {
					String baseLocation = getReaderContext().getResource().getURL().toString();
					// 将地址传入进行具体解析
					importCount = getReaderContext().getReader().loadBeanDefinitions(
							StringUtils.applyRelativePath(baseLocation, location), actualResources);
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
				}
			}
			catch (IOException ex) {
				getReaderContext().error("Failed to resolve current resource location", ele, ex);
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
						ele, ex);
			}
		}
		// actualResources 用于保存所有已经解析过的 Resource 资源
		Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
		getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
	}

AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources)

org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String location, Set< Resource> actualResources)

  • 这个方法内部则是调用我们之前分析的方法 Spring源码学习:reader.loadBeanDefinitions(configLocation).所以可以看出,import 标签的解析是一个大循环。
  • 但是相比之下,多了一个参数 Set< Resource> actualResources,该参数用于保存方法内部解析过的 Resource 资源,由于该方法返回值只能有一个,所以这里运用了Java 中的引用传递的知识。
/**
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 * @see #getResourceLoader()
	 * @see #loadBeanDefinitions(org.springframework.core.io.Resource)
	 * @see #loadBeanDefinitions(org.springframework.core.io.Resource[])
	 */
	public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
		}
		//如果资源是通配符类型-即可以解析为多个资源
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			try {
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				//这里调用我们之前分析过的方法,所以 import 引用文件是一个大循环
				// https://blog.csdn.net/bestcxx/article/details/100185664
				int loadCount = loadBeanDefinitions(resources);
				//actualResources 必须在方法外就实例化了,否则根据引用传递的规律,方法外无法获得被修改的实例,将解析出的 resource 对象添加到 actualResources 
				if (actualResources != null) {
					for (Resource resource : resources) {
						actualResources.add(resource);
					}
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
				}
				return loadCount;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// 否则就是绝对路径,仅能解析出一个资源
			Resource resource = resourceLoader.getResource(location);
			//这里调用我们之前分析过的方法,所以 import 引用文件是一个大循环
			// https://blog.csdn.net/bestcxx/article/details/100185664
			int loadCount = loadBeanDefinitions(resource);
			//actualResources 必须在方法外就实例化了,否则根据引用传递的规律,方法外无法获得被修改的实例,将解析出的 resource 对象添加到 actualResources 
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
			}
			return loadCount;
		}
	}

beans标签

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(

  • 对于 beans 标签的解析其实只有在应用 profile 功能时才会用到,即Spring 的版本功能,这个我们在前一篇中也已经讲到,这里不再赘述,请移步 DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(:解析 beans 标签
    beans 标签内部也是一个嵌套,是一个比 import 更外围的嵌套
<beans profile="">
        <bean>bean>
        <import resource="">import>
    beans>

alias标签

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processAliasRegistration(

  • alias 标签允许给一个bean起一个别名。
  • 不允许出现循环起别名,比如 a指向b,b指向c,c又指向a这种,即alias可以表示alias,但是最终必须指定到一个具体bean
  • alias 的使用和正常bean一样,比如使用 @Qualifier(“demo1”)
   
    <alias name="demo" alias="demo1">alias>
    <bean id="demo" class="a.b.c">bean>

看源码

	protected void processAliasRegistration(Element ele) {
		String name = ele.getAttribute(NAME_ATTRIBUTE);
		String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
		boolean valid = true;
		if (!StringUtils.hasText(name)) {
			getReaderContext().error("Name must not be empty", ele);
			valid = false;
		}
		if (!StringUtils.hasText(alias)) {
			getReaderContext().error("Alias must not be empty", ele);
			valid = false;
		}
		if (valid) {
			try {
			    //将 给定的bean 和 alias 进行注册
				getReaderContext().getRegistry().registerAlias(name, alias);
			}
			catch (Exception ex) {
				getReaderContext().error("Failed to register alias '" + alias +
						"' for bean with name '" + name + "'", ele, ex);
			}
			getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
		}
	}

SimpleAliasRegistry.registerAlias(

org.springframework.core.SimpleAliasRegistry.registerAlias
注册 alias,不允许出现循环 alias的情况,即alias最后必须落实到一个具体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");
		if (alias.equals(name)) {
			this.aliasMap.remove(alias);
		}
		else {
			String registeredName = this.aliasMap.get(alias);
			if (registeredName != null) {
				if (registeredName.equals(name)) {
					// alias 已经存在,无需重新注册
					return;
				}
				//如果不允许重复注册则抛出异常-同一个 alias 仅允许注册一次
				if (!allowAliasOverriding()) {
					throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
							name + "': It is already registered for name '" + registeredName + "'.");
				}
			}
			//检查是否存在 Alias循环,防止 a表示b,b表示c,c又表示a这种
			checkForAliasCircle(name, alias);
			this.aliasMap.put(alias, name);
		}
	}

真正对bean解析的只有 bean标签

源码看到这里,我们可以了解到,在初始化阶段,对配置文件的解析虽然分为了 import、alias、bean、beans四种,但是beans 相当于对 profile 的解析,import相当于对新配置文件的解析,alias只是给bean起一个别名,而真正的重头戏在于对bean标签的解析。

DefaultBeanDefinitionDocumentReader.processBeanDefinition(:bean标签的处理

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(

  • 该方法才是处理具体bean的定义( bean definition)和注册的逻辑,该步骤之后,配置文件中的bean会被注册到 registry。

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	    //将 Element 转化为 BeanDefinitionHolder
	    //BeanDefinitionHolder包含三项信息,bean定义相关信息,bean名称,bean的别名数组 alias
	    //如果转化过程有错误则得到null
	    //需要注意的是,同一个 beans 内并不允许有重名bean存在,加载阶段就会检查
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			//对 bdHolder 进行装饰,即解析 bean和子 标签中的 其他属性标签,比如autowire 用户自定义的标签等
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				//注册最终被装饰好的 类实体
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele):将 bean 标签解析为 BeanDefinitionHolder

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionElement(
在这个方法中Spring会将bean标签以及其内在的 id、name等属性封装到 BeanDefinitionHolder 对象中,该方法可能返回null

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
		return parseBeanDefinitionElement(ele, null);
	}
BeanDefinitionHolder:bean定义信息和名称、别名

org.springframework.beans.factory.config.BeanDefinitionHolder
element 会先被转化为 BeanDefinitionHolder 对象
该对象包含三项信息:bean定义相关信息,bean名称,bean的别名数组 alias

	/**beanDefinition 包含对bean的相关定义信息,比如是否单例、是都懒加载、构造函数、set参数等*/
	private final BeanDefinition beanDefinition;
	/**bean的名称*/
	private final String beanName;
	/**别名数组*/
	private final String[] aliases;

BeanDefinition:Spring bean的定义信息:如scope、lazy-init

org.springframework.beans.factory.config.BeanDefinition
包含对一个Spring bean的具体化的定义信息,比如scope、lazy-init、primary、构造参数、set参数等。
还有一个我们平时不会注意到的属性 role,在允许覆盖bean时,该值会作为判断bean定义范围的依据,用于打印日志时使用

/**
	 * 表示这个 beanDefiniton 是应用的重要的一部分,一般是用户自定义的bean的默认 role值
	 */
	int ROLE_APPLICATION = 0;

	/**
	 * Role hint indicating that a {@code BeanDefinition} is a supporting
	 * part of some larger configuration, typically an outer
	 * {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
	 * {@code SUPPORT} beans are considered important enough to be aware
	 * of when looking more closely at a particular
	 * {@link org.springframework.beans.factory.parsing.ComponentDefinition},
	 * but not when looking at the overall configuration of an application.
	 */
	int ROLE_SUPPORT = 1;

	/**
	 * Role hint indicating that a {@code BeanDefinition} is providing an
	 * entirely background role and has no relevance to the end-user. This hint is
	 * used when registering beans that are completely part of the internal workings
	 * of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
	 */
	int ROLE_INFRASTRUCTURE = 2;
BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)
  • bean标签可以配置 id和name属性。
  • name属性会转化为 alias 别名集合(List类型)
  • Spring 对于一个 bean 的名字的获取的逻辑:beanName默认为id属性值,如果id为空并且name属性值不为空,则取name属性转换为 alias 集合(List类型)的第一个值作为name,并且将alias中第一个值去掉——即同一个值仅可以作为bean或者alias一次进行注册。如果id和name属性都是空,则取该bean的类名按照Spring的命名规则生成bean的名字。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		//name属性值转为 alias 集合
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		//默认 beanName 取id属性值
		String beanName = id;
		//如果id属性为空,且name属性转化的 alias属性存在,则取alias集合第一个值作为beanName
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}
		//默认会走这块逻辑-检查 beanName的唯一性
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		//各种bean标签的解析,如 singleton、scope、abstract、lazy-init、autowire、dependency-check、depends-on、autowire-candidate、primary、init-method、destroy-method、factory-method、factory-bean
		//子类替换方法
		//描述信息 decription
		//元数据类型 meta ,key value
		//构造函数参数 constructor-arg
		//set类型参数 property
		//qualifier类型
		//beanName和alias会被记录到 usedName,用于检测 同beans中所有唯一的bean的名字或别名
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			//如果 beanName 没有获取到-则生成 beanName
			if (!StringUtils.hasText(beanName)) {
				try {
				//实际源码中 入参 containingBean  会是 null 
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
					//这一段是实际的Spring 生成默认 beanName的逻辑,得到一个类的全限定名#数字,如 com.bestcxx.cn.webrecord.controller.LoginController#0
						beanName = this.readerContext.generateBeanName(beanDefinition);
						//获取类的全限定名
						String beanClassName = beanDefinition.getBeanClassName();
						//如果类的全限定名满足下面的条件-则将类的全限定名注册为 alias
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			//将 beanName,alias 赋值到 beanDefinition
			//beanName 为 类全限定名#数字
			//alias为 类全限定名
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
默bean 标签生成beanName的逻辑:类全限定名#数字

跟踪源码可以发现,Spring 对于< bean>标签按照 id、name属性来确定BeanName,但是如果没有指定就要用默认的逻辑了。
默认的beanName为 全限定名#数字,如 com.bestcxx.cn.webrecord.controller.LoginController#0
结合外围代码,满足某种条件,还会将类全限定名作为 alia注册。
比如对于下面的bean定义

 <bean class="com.bestcxx.cn.webrecord.controller.LoginController" >bean>

进入源码

public static String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {
		return generateBeanName(beanDefinition, registry, false);
	}

从上一段可以知道 isInnerBean 为false

public static String generateBeanName(
			BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
			throws BeanDefinitionStoreException {
		//获取 class 属性 ,这里就是com.bestcxx.cn.webrecord.controller.LoginController
		String generatedBeanName = definition.getBeanClassName();
		if (generatedBeanName == null) {
			//如果没有定义,就获取 defination的父类名,增加 $child后缀
			if (definition.getParentName() != null) {
				generatedBeanName = definition.getParentName() + "$child";
			}
			//否则,就获取 defination的 factoryBean名,增加 $created 后缀
			else if (definition.getFactoryBeanName() != null) {
				generatedBeanName = definition.getFactoryBeanName() + "$created";
			}
		}
		//如果还获取不到,则报错
		if (!StringUtils.hasText(generatedBeanName)) {
			throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
					"'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
		}
		String id = generatedBeanName;
		//源码里这个入参为 false
		if (isInnerBean) {
			id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
		}
		else {
			// Top-level bean: use plain class name.
			// 累加 counter 知道 bean 是唯一的 
			int counter = -1;
			while (counter == -1 || registry.containsBeanDefinition(id)) {
				counter++;
				//得到类似于 com.bestcxx.cn.webrecord.controller.LoginController#0
				id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
			}
		}
		return id;
	}

BeanDefinitionReaderUtils.registerBeanDefinition(:注册每一个bean相关信息:scope、注入方式、alias等

org.springframework.beans.factory.support.BeanDefinitionReaderUtils.registerBeanDefinition(

  • 将bean definition 注册到对应的 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 {

		// 获取 bean definition 中bean的名字
		String beanName = definitionHolder.getBeanName();
		// 将bean进行注册
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// 如果有必要的话,注册 bean 的 alias (别名),这里alias产生的途径可能是自定义的 name,也可能是没有声明 id和name时Spring自动生成的
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
DefaultListableBeanFactory.registerBeanDefinition(:检查同名bean的覆盖操作就在这里哟

org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(

真正注册bean的功能居然是写在 DefaultListableBeanFactory 中的,我们之前有对其进行简单的介绍 认识 DefaultListableBeanFactory,其包含了很多重要的属性的定义。
该方法用于检查bean的重复覆盖操作;

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
		//bean 和 definition 不可为 空
		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		
		BeanDefinition oldBeanDefinition;
		//尝试获取 同 beanName 的 beanDefinition
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		//如果已经存在同名的 beanDefinition-说明注册过了
		if (oldBeanDefinition != null) {
			
			if (!isAllowBeanDefinitionOverriding()) {
				//Spring 默认允许覆盖其他 beans 注册的 beanDefinition,如果设置为不允许则抛出异常
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			// 
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//如果允许覆盖,不同情况下日志打印不同,然后都会用后注册的 bean覆盖之前的同名 beanDefinition
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			//判断该 beanDefiniton 是否已经开始创建-即将进入同步方法
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}
AbstractBeanFactory.hasBeanCreationStarted()

org.springframework.beans.factory.support.AbstractBeanFactory.hasBeanCreationStarted()

判断创建 Bean 的过程是否已经开始

protected boolean hasBeanCreationStarted() {
		//alreadyCreated:至少被创建一次的 beanName set集合
		return !this.alreadyCreated.isEmpty();
	}

看下这个类中的其他的变量

/** Parent bean factory, for bean inheritance support */
	private BeanFactory parentBeanFactory;

	/** ClassLoader to resolve bean class names with, if necessary */
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/** ClassLoader to temporarily resolve bean class names with, if necessary */
	private ClassLoader tempClassLoader;

	/** Whether to cache bean metadata or rather reobtain it for every access */
	private boolean cacheBeanMetadata = true;

	/** Resolution strategy for expressions in bean definition values */
	private BeanExpressionResolver beanExpressionResolver;

	/** Spring ConversionService to use instead of PropertyEditors */
	private ConversionService conversionService;

	/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
	private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
			new LinkedHashSet<PropertyEditorRegistrar>(4);

	/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
	private TypeConverter typeConverter;

	/** Custom PropertyEditors to apply to the beans of this factory */
	private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
			new HashMap<Class<?>, Class<? extends PropertyEditor>>(4);

	/** String resolvers to apply e.g. to annotation attribute values */
	private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();

	/** BeanPostProcessors to apply in createBean */
	private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

	/** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */
	private boolean hasInstantiationAwareBeanPostProcessors;

	/** Indicates whether any DestructionAwareBeanPostProcessors have been registered */
	private boolean hasDestructionAwareBeanPostProcessors;

	/** Map from scope identifier String to corresponding Scope */
	private final Map<String, Scope> scopes = new LinkedHashMap<String, Scope>(8);

	/** Security context used when running with a SecurityManager */
	private SecurityContextProvider securityContextProvider;

	/** Map from bean name to merged RootBeanDefinition */
	private final Map<String, RootBeanDefinition> mergedBeanDefinitions =
			new ConcurrentHashMap<String, RootBeanDefinition>(256);

	/** 至少被创建一次的 beanName set集合 */
	private final Set<String> alreadyCreated =
			Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(256));

	/** Names of beans that are currently in creation */
	private final ThreadLocal<Object> prototypesCurrentlyInCreation =
			new NamedThreadLocal<Object>("Prototype beans currently in creation");


你可能感兴趣的:(beans,bean,profile,alias,Spring,源码学习)