spring中默认标签Bean标签解析二

回顾一下上一节的入口代码

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 1、解析bean标签
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// 2、如果bdHolder不为空的时候存在默认标签的子节点下再有自定义属性,需要进行进一步的处理
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				// 3、注册BeanDefinition
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			// 4、发布bean加载完成事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

上一篇文章主要讲的是默认标签中的解析.主要讲的是bean标签里的属性解析.也就是上面的第一步.
下面继续介绍第二步的解析.
根据注释我们大概知道第二步主要是判断默认标签的子节点里边有没有自定义属性,如果有需要进一步的解析,否则不做操作.
举个例子:

<bean id="myBean" class="com.ipluto.MyBean">
	<mytest:cat catColor="black">
</bean>

在这种场景下,bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)就会起作用.
上代码:

	
	public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
		return decorateBeanDefinitionIfRequired(ele, originalDef, null);
	}

注意上面方法里的第三个参数,第三个参数是父类bean,当某个嵌套配置进行分析时,这里需要传递父类beanDefinition.分析源码得知这里传递的参数其实是为了使用父类的scope属性,以备子类没有设置scope时默认使用父类的属性,这里分析的是顶层配置,所以传递null.

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
			Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

		BeanDefinitionHolder finalDefinition = originalDef;

		// Decorate based on custom attributes first.
		// 获取元素的属性,对属性进行处理
		NamedNodeMap attributes = ele.getAttributes();
		for (int i = 0; i < attributes.getLength(); i++) {
			Node node = attributes.item(i);
			finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
		}

		// Decorate based on custom nested elements.
		// 获取元素的子元素,对子元素进行解析
		NodeList children = ele.getChildNodes();
		for (int i = 0; i < children.getLength(); i++) {
			Node node = children.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
			}
		}
		return finalDefinition;
	}

public BeanDefinitionHolder decorateIfRequired(
			Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
		// 1、获取节点的命名空间
		String namespaceUri = getNamespaceURI(node);
		// 2、判断是不是默认命名空间
		if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
			// 2.1、寻找对应命名空间的handler
			NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
			// 2.2、找到进行decorate
			if (handler != null) {
				BeanDefinitionHolder decorated =
						handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
				if (decorated != null) {
					return decorated;
				}
			}
			// 2.3、没有找到,并且以指定地址开头,则抛异常
			else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
				error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
			}
			// 2.4、没有找到,不做处理
			else {
				// A custom namespace, not to be handled by Spring - maybe "xml:...".
				if (logger.isDebugEnabled()) {
					logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
				}
			}
		}
		return originalDef;
	}

这里的第2.1步其实就是前面提到的自定义标签的解析,这个会在自定义标签里面详细讲解.
回到最开始的入口代码,我们现在第二步也已经看完了.
接下来就是把解析好的beanDefinition注册到容器中.

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		// 1、注册BeanDefinition
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				// 2、注册别名
				registry.registerAlias(beanName, alias);
			}
		}
	}

其实beanDefinition注册核心就是把对应的东西放到一个容器里面,对于beanDefinition的注册,是把beanDefinition放到一个 map里边,map的key是beanName,value就是beanDefintion.
beanDefinition的注册

@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 {
			    //  这里主要校验AbstractBeanDefinition属性中的methodOverrides校验
			    // 校验methodOverrides是否于工厂方法并存或者methodOverrides对应的方法根本不存在
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		// 先从容器中获取,看看是否已经存在beanDefinition
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			// 如果已经存在,就要看这个属性值
			// 这个属性的意思是是否允许同名的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 {
			// 容器中没有对应的beanDefinition
			// 判断是否有bean标记为已创建
			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<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			// 没有创建则直接操作
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		// 如果存在beanDefinition或者已经创建了单例,需要重置beanName对应的缓存
		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
		// 清除缓存
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}

注意这里的hasBeanCreationStarted()判断,根据源码来看,只是判断AbstractBeanfactory的alreadyCreated属性是不是空的.
alreadyCreated属性保存的是已经至少创建过一次的bean名称
如果不是空的,说明已经开始进行业务操作,Spring容器无法保证下面的操作不会出现线程安全问题,所以需要加锁.

总结一下上面的操作就是
1、对abstractBeanDefinition的methodOverride进行校验
2、获取容器中是否已经存在beanName对应的beanDefinition了
2.1如果存在需要进一步判断allowBeanDefinitionOverriding的值
如果allowBeanDefinitionOverriding为true则进行覆盖
否则抛出异常
2.2如果不存在则需要进一步判断需不需要加锁
如果hasBeanCreationStarted为true则需要加锁
反之不需要加锁
3、最后的清理判断

aliases的注册

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 {
			    // 获取缓存中的beanName
				String registeredName = this.aliasMap.get(alias);
				if (registeredName != null) {
					// 如果不为空且等于当前bean的名字,则说明已经注册过了,不做操作
					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 + "'");
					}
				}
				// alias循环检查
				checkForAliasCircle(name, alias);
				// 注册alias
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

注意,这里特别分析一下alias的循环检查checkForAliasCircle(name, alias);

	protected void checkForAliasCircle(String name, String alias) {
		// 当这里返回true的时候,说明有循环依赖
		// 大家注意一点:这里传入的值是alias、name
		// 进入到这个方法的时候,你会发现他俩的参数名称是反过来的一定要注意
		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");
		}
	}

hasAlias

	public boolean hasAlias(String name, String alias) {
		// 这里的name其实是要注册的alias
		// 而这里的alias其实是 `name` 对应的beanName
		String registeredName = this.aliasMap.get(alias);
		return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
				&& hasAlias(name, registeredName));
	}

根据判断
1、只要registedName等于name的话,就会返回true
2、或者递归寻找间接循环
举个例子:

  • 直接循环:
    首先有name是A的别名是C,表示为A->C.
    这个时候如果再有name是C的别名是A的时候,表示为 C->A,就是出现直接依赖.
    因为name是C,别名是A的时候,方法checkForAliasCircle的参数是name=C、alias=A;
    那么hasAlias的参数就是name=A、alias=C
    则从aliasMap中得到registeredName = A,则name=registeredName,返回了true,抛出异常.
  • 间接循环
    有name=A、alias=B,name=B、alias=C,则aliasMap存储的两个键值对是(B,A)、(C,B)
    当这个时候又有一个bean的name=C,alias=A的时候,方法checkForAliasCircle的参数是name=C,alias=A;
    那么hasAlias的参数就是name=A、alias=C;
    则从aliasMap中得到registeredName = B,此时name!=registeredName,继续递归调用hasAlias,参数是name=A,alias=registeredName=B;
    则从aliasMap中得到registeredName = A,则name=registeredName=A,返回true抛出了异常.

上面的过程就是描述了alias的循环实现的过程.
好了到这里beanDefinition就注册完成了
最后是一个事件发布

	public void fireComponentRegistered(ComponentDefinition componentDefinition) {
		this.eventListener.componentRegistered(componentDefinition);
	}

到这里bean标签的解析就结束了.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值