上一篇文章讲到了标签在 parseDefaultElement 方法中进行解析,本篇文章将讲解这部分内容

bean 标签解析

查看 processBeanDefinition 方法,针对各个操作作具体分析:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 1.解析 BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

1. 解析 BeanDefinition

首先从元素解析及信息提取开始,进入 parseBeanDefinitionElement 方法

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
} public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 1.1 解析id属性
String id = ele.getAttribute("id");
// 1.2 解析name属性
String nameAttr = ele.getAttribute("name");
List<String> aliases = new ArrayList();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
} String beanName = id;
if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
} if (containingBean == null) {
this.checkNameUniqueness(beanName, aliases, ele);
}
// 2. 解析其他属性
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
// 3. 如果不存在beanName就根据Spring提供的命名规则为当前bean生成对应的beanName
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
} if (this.logger.isTraceEnabled()) {
this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
} String[] aliasesArray = StringUtils.toStringArray(aliases);
// 4. 封装到 BeanDefinitionHolder 的实例
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}

该方法完成的主要工作包括以下内容:

  1. 提取元素中的 id 以及 name 属性
  2. 进一步解析其他属性并统一封装至 GenericBeanDefinition 类型的实例中
  3. 如果检测到 bean 没有指定 beanName,那么使用默认规则为此 Bean 生成 beanName
  4. 将获取到的信息封装到 BeanDefinitionHolder 的实例中

进一步查看步骤二对标签的其他属性的解析过程:

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
// 解析class属性
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
// 解析parent属性
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
} try {
// 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition实例
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
// 硬编码解析默认bean的各种属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 提取description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
// 解析元数据
this.parseMetaElements(ele, bd);
// 解析lookup-method属性
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method属性
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析构造函数参数
this.parseConstructorArgElements(ele, bd);
// 解析property子元素
this.parsePropertyElements(ele, bd);
// 解析qualifier子元素
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
AbstractBeanDefinition var7 = bd;
return var7;
} catch (ClassNotFoundException var13) {
this.error("Bean class [" + className + "] not found", ele, var13);
} catch (NoClassDefFoundError var14) {
this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
} catch (Throwable var15) {
this.error("Unexpected failure during bean definition parsing", ele, var15);
} finally {
this.parseState.pop();
} return null;
}

接下来,我们继续一些复杂标签属性的解析:

1.1 创建用于属性承载的 BeanDefinition

BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition,三种实现类均继承了 AbstractBeanDefinition

BeanDefinition 是配置文件 <bean> 元素标签在容器中的内部表示形式,<bean> 标签拥有 class、scope、lazy-init 等配置属性,BeanDefinition 就提供了对应的 beanClass、scope、lazyInit 属性

由此可见,要解析属性首先要创建用于承载属性的实例,也就是创建 GenericBeanDefinition 类型的实例,createBeanDefinition 方法的作用就是实现此功能

public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
// 如果classLoader不为空,则使用传入的classLoader加载对象
// 否则就只是记录className
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
} else {
bd.setBeanClassName(className);
}
} return bd;
}
2. 解析各种属性

当我们创建了 bean 信息的承载实例后,便可以进行 bean 信息的各种属性解析了,parseBeanDefinitionAttributes 方法是对 element 所有元素属性进行解析:

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析scope属性
if (ele.hasAttribute("singleton")) {
this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute("scope")) {
bd.setScope(ele.getAttribute("scope"));
} else if (containingBean != null) {
bd.setScope(containingBean.getScope());
}
// 解析singleton属性
if (ele.hasAttribute("abstract")) {
bd.setAbstract("true".equals(ele.getAttribute("abstract")));
}
// 解析lazy-init属性
String lazyInit = ele.getAttribute("lazy-init");
if (this.isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
// 若没有设置或设置成其他字符都会被设置为false
bd.setLazyInit("true".equals(lazyInit));
String autowire = ele.getAttribute("autowire");
bd.setAutowireMode(this.getAutowireMode(autowire));
String autowireCandidate;
if (ele.hasAttribute("depends-on")) {
autowireCandidate = ele.getAttribute("depends-on");
bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
}
// 解析autowire属性
autowireCandidate = ele.getAttribute("autowire-candidate");
String destroyMethodName;
if (this.isDefaultValue(autowireCandidate)) {
destroyMethodName = this.defaults.getAutowireCandidates();
if (destroyMethodName != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
} else {
bd.setAutowireCandidate("true".equals(autowireCandidate));
}
// 解析primary属性
if (ele.hasAttribute("primary")) {
bd.setPrimary("true".equals(ele.getAttribute("primary")));
}
// 解析init-method属性
if (ele.hasAttribute("init-method")) {
destroyMethodName = ele.getAttribute("init-method");
bd.setInitMethodName(destroyMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 解析destroy-method属性
if (ele.hasAttribute("destroy-method")) {
destroyMethodName = ele.getAttribute("destroy-method");
bd.setDestroyMethodName(destroyMethodName);
} else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
// 解析factory-method属性
if (ele.hasAttribute("factory-method")) {
bd.setFactoryMethodName(ele.getAttribute("factory-method"));
}
// 解析factory-bean属性
if (ele.hasAttribute("factory-bean")) {
bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
}
return bd;
}

注册解析的 BeanDefinition

得到 BeanDefinition 后,剩下的工作就是注册了,也就是 processBeanDefinition 方法中的

registerBeanDefinition 方法

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try {
// 注册解析的 BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
} public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 使用beanName做唯一标识注册
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 注册所有的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}

解析的 beanDefinition 都会被注册到 BeanDefinitionRegistry 类型的实例 registry 中,而对于 beanDefinition 的注册分成两个部分:通过 beanName 注册以及通过别名注册

1. 通过 beanName 注册

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)beanDefinition).validate();
} catch (BeanDefinitionValidationException var8) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
}
}
// 处理beanName已经注册的情况
BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 如果对应BeanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常
if (!this.isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
} if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isInfoEnabled()) {
this.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 (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
}
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
} this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// 检查工厂是否处于bean创建阶段
if (this.hasBeanCreationStarted()) {
// 因为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;
this.removeManualSingletonName(beanName);
}
} else {
// 注册beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// 记录beanName
this.beanDefinitionNames.add(beanName);
this.removeManualSingletonName(beanName);
} this.frozenBeanDefinitionNames = null;
} if (existingDefinition == null && !this.containsSingleton(beanName)) {
if (this.isConfigurationFrozen()) {
this.clearByTypeCache();
}
} else {
this.resetBeanDefinition(beanName);
}
}

在对于 bean 的注册处理方式上,主要进行了几个步骤:

  1. 对 AbstractBeanDefinition 校验
  2. 加入 map 缓存
  3. 清楚解析之前留下的对应的 beanName 的缓存

2. 通过别名注册 BeanDefinition

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 (this.logger.isDebugEnabled()) {
this.logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
} else {
String registeredName = (String)this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
return;
} if (!this.allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
} if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'");
}
}
// 检查是否存在循环指向,如A->B,A->C->B
this.checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}

注册 alias 的步骤如下:

  1. alias 与 beanName 相同情况处理
  2. alias 循环检查
  3. 注册 alias

Spring Bean 标签解析的更多相关文章

  1. Spring源码学习笔记之基于ClassPathXmlApplicationContext进行bean标签解析

    bean 标签在spring的配置文件中, 是非常重要的一个标签, 即便现在boot项目比较流行, 但是还是有必要理解bean标签的解析流程,有助于我们进行 基于注解配置, 也知道各个标签的作用,以及 ...

  2. Spring自定义标签解析与实现

           在Spring Bean注册解析(一)和Spring Bean注册解析(二)中我们讲到,Spring在解析xml文件中的标签的时候会区分当前的标签是四种基本标签(import.alias ...

  3. Spring Bean注册解析(二)

           在上文Spring Bean注册解析(一)中,我们讲解了Spring在注册Bean之前进行了哪些前期工作,以及Spring是如何存储注册的Bean的,并且详细介绍了Spring是如何解析 ...

  4. bean标签解析与注册

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefin ...

  5. Spring Bean注册解析(一)

           Spring是通过IoC容器对Bean进行管理的,而Bean的初始化主要分为两个过程:Bean的注册和Bean实例化.Bean的注册主要是指Spring通过读取配置文件获取各个bean的 ...

  6. 【转】Spring Bean属性解析

    转载自:http://wenku.baidu.com/view/30c7672cb4daa58da0114ae2.html Bean所以属性一览: <bean id="beanId&q ...

  7. Spring<bean>标签是反射来实现的

  8. spring bean标签常用属性

    一.id属性 其名称,可以是任意名称,但不能包含特殊符号. 根据id得到配置对象. 二.class属性 创建对象所在的类名称 三.name属性 功能和id属性一样,但name属性值可以包含特殊属性 四 ...

  9. 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程

    原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...

随机推荐

  1. Halo 开源项目学习(六):事件监听机制

    基本介绍 Halo 项目中,当用户或博主执行某些操作时,服务器会发布相应的事件,例如博主登录管理员后台时发布 "日志记录" 事件,用户浏览文章时发布 "访问文章" ...

  2. 【CSAPP】Bomb Lab实验笔记

    bomblab这节搞的是二进制拆弹,可以通俗理解为利用反汇编知识找出程序的六个解锁密码. 早就听闻BOMBLAB的大名,再加上我一直觉得反汇编是个很艰难的工作,开工前我做好了打BOSS心理准备.实际上 ...

  3. Open Harmony移植:build lite配置目录全梳理

    摘要:本文主要介绍build lite 轻量级编译构建系统涉及的配置目录的用途,分析相关的源代码. 本文分享自华为云社区<移植案例与原理 - build lite配置目录全梳理>,作者:z ...

  4. 关闭BottomSheetDialogFragment从后台返回后的动画

    问题 显示BottomSheetDialogFragment后.将当前应用放于后台,切换到其他APP,然后再返回当前应用.此时会看到BottomSheetDialogFragment从下而上的动画再次 ...

  5. WPF 制作雷达扫描图

    实现一个雷达扫描图. 源代码在TK_King/雷达 (gitee.com),自行下载就好了 制作思路 绘制圆形(或者称之轮) 绘制分割线 绘制扫描范围 添加扫描点 具体实现 首先我们使用自定义的控件. ...

  6. pytorch入门--土堆深度学习快速入门教程

    工具函数 dir函数,让我们直到工具箱,以及工具箱中的分隔区有什么东西 help函数,让我们直到每个工具是如何使用的,工具的使用方法 示例:在pycharm的console环境,输入 import t ...

  7. GET 与 POST 其实没有什么区别

    GET 与 POST 其实没有什么区别 本文写于 2020 年 12 月 30 日 GET 与 POST 是两种 HTTP 方法,并且是最常用的两种. 今天在使用 Postman 测试 api 的时候 ...

  8. 使用echo 无法正确清空文件存储大小

    在使用echo进行重定向文件的时候,会存在大小没有发生改变的现象 使用上面的方法遇到一个现象 ls -l 与 du -sh 得到的大小事是不同的 可以尝试下面的方面之后在进行对比 再看是否正确清除 使 ...

  9. Mac-Typora快捷键

    标题(大钢) command+(1-6)) 如:command+1,设置为一级标题 引用 快捷键:command+option+Q 或者:先">",后面直接加内容 二级引用: ...

  10. 安装Zabbix到Ubuntu(APT)

    运行环境 系统版本:Ubuntu 16.04.2 LTS 软件版本:Zabbix-4.0.2 硬件要求:无 安装过程 1.安装APT-Zabbix存储库 APT-Zabbix存储库由Zabbix官网提 ...