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);}}

这里主要分新bean标签的处理,其他都类似

/*** Process the given bean element, parsing the bean definition* and registering it with the registry.*/protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 首先委托 BeanDefinitionParserDelegate 类的parseBeanDefinitionElement方法进行元素的解析,返回实例BeanDefinitionHolder 对象,经过这个方法后,bdHolder实例已经包含我们配置的配置文件中的各种属性了,列如:class,id,alias之类的属性了。BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {
// 当返回的BeanDefinitionHolder对象实例 bdHolder不为空的情况下若存在默认标签的字节点下再有自定义属性,还需要再次对自定义属性进行解析。bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.
//解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法。
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.
//最后发出响应事件,通知相关的监听器,这个bean已经加载完成了。getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}}

继续深入分析 BeanDefinitionParserDelegate 类的parseBeanDefinitionElement方法:

/*** Parses the supplied {@code <bean>} element. May return {@code null}* if there were errors during parse. Errors are reported to the* {@link org.springframework.beans.factory.parsing.ProblemReporter}.*/public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {// 解析id属性String id = ele.getAttribute(ID_ATTRIBUTE);// 解析name属性String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);// 分隔name属性 List<String> aliases = new ArrayList<String>();if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);aliases.addAll(Arrays.asList(nameArr));}String beanName = id;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");}}if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);}// 进一步解析bean的其他属性 并封装到对象 GenericBeanDefinition对象中AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);if (beanDefinition != null) {if (!StringUtils.hasText(beanName)) {try {if (containingBean != null) {// 如果不存在 beanName,则使用Spring提供的命名规则默认生成beanNamebeanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);}else {// 如果有则获取beanNamebeanName = this.readerContext.generateBeanName(beanDefinition);// Register an alias for the plain bean class name, if still possible,// if the generator returned the class name plus a suffix.// This is expected for Spring 1.2/2.0 backwards compatibility.String beanClassName = beanDefinition.getBeanClassName();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);            // 将获取到的信息封装到 BeanDefinitionHolder 实例中去
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }

接下来进一步分析对其他bean标签的解析方法:

AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

/*** Parse the bean definition itself, without regard to name or aliases. May return* {@code null} if problems occurred during the parsing of the bean definition.*/public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {this.parseState.push(new BeanEntry(beanName));String className = null;// 解析class属性if (ele.hasAttribute(CLASS_ATTRIBUTE)) {className = ele.getAttribute(CLASS_ATTRIBUTE).trim();}try {String parent = null;// 解析parent属性if (ele.hasAttribute(PARENT_ATTRIBUTE)) {parent = ele.getAttribute(PARENT_ATTRIBUTE);}// 创建用于承载bean各种标签的 GenericBeanDefinition对象AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 硬编码解析bean的属性 例如:singleton、destroy-method等
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);// 提取 desciption
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));// 解析元数据
            parseMetaElements(ele, bd);// 解析lookup-method属性
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());// 解析repalce-method属性
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());// 解析构造函数参数
            parseConstructorArgElements(ele, bd);// 解析property字元素
            parsePropertyElements(ele, bd);// 解析qualifier子元素
            parseQualifierElements(ele, bd);bd.setResource(this.readerContext.getResource());bd.setSource(extractSource(ele));return bd;}catch (ClassNotFoundException ex) {error("Bean class [" + className + "] not found", ele, ex);}catch (NoClassDefFoundError err) {error("Class that bean class [" + className + "] depends on not found", ele, err);}catch (Throwable ex) {error("Unexpected failure during bean definition parsing", ele, ex);}finally {this.parseState.pop();}return null;}

进一步分析创建属性承载的BeanDefinition对象

BeanDefinition是一个接口,spring中三种实现形式:RootBeanDefinition、ChildBeanDefinition和GenericBeanDefinition。三种实现类均继承了AbstractBeanDefinition,其中BeanDefinition是<bean>标签在容器内部的表现形式,BeanDefinition和<bean>的属性是一一对应的。Spring通过BeanDefinition将配置文件中的信息装换为内部的表现形式,并将这些BeanDefinition注册到BeanDefinitionRegistry中。

至此 已经完成XML文档像GenericBeandefinition的全部装换。GenericBeandefinition只是子类实现,大部分属性封装在AbstractBeandefinition对象中,我们继续分析AbstractBeandefinition的给中属性:

@SuppressWarnings("serial")
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessorimplements BeanDefinition, Cloneable {/*** Constant for the default scope name: {@code ""}, equivalent to singleton* status unless overridden from a parent bean definition (if applicable).*/public static final String SCOPE_DEFAULT = "";/*** Constant that indicates no autowiring at all.* @see #setAutowireMode*/public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;/*** Constant that indicates autowiring bean properties by name.* @see #setAutowireMode*/public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;/*** Constant that indicates autowiring bean properties by type.* @see #setAutowireMode*/public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;/*** Constant that indicates autowiring a constructor.* @see #setAutowireMode*/public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;/*** Constant that indicates determining an appropriate autowire strategy* through introspection of the bean class.* @see #setAutowireMode* @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,* use annotation-based autowiring for clearer demarcation of autowiring needs.*/@Deprecatedpublic static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;/*** Constant that indicates no dependency check at all.* @see #setDependencyCheck*/public static final int DEPENDENCY_CHECK_NONE = 0;/*** Constant that indicates dependency checking for object references.* @see #setDependencyCheck*/public static final int DEPENDENCY_CHECK_OBJECTS = 1;/*** Constant that indicates dependency checking for "simple" properties.* @see #setDependencyCheck* @see org.springframework.beans.BeanUtils#isSimpleProperty*/public static final int DEPENDENCY_CHECK_SIMPLE = 2;/*** Constant that indicates dependency checking for all properties* (object references as well as "simple" properties).* @see #setDependencyCheck*/public static final int DEPENDENCY_CHECK_ALL = 3;/*** Constant that indicates the container should attempt to infer the* {@link #setDestroyMethodName destroy method name} for a bean as opposed to* explicit specification of a method name. The value {@value} is specifically* designed to include characters otherwise illegal in a method name, ensuring* no possibility of collisions with legitimately named methods having the same* name.* <p>Currently, the method names detected during destroy method inference* are "close" and "shutdown", if present on the specific bean class.*/public static final String INFER_METHOD = "(inferred)";private volatile Object beanClass;// bean的作用范围,对应bean的属性 scopeprivate String scope = SCOPE_DEFAULT;// 是否抽象标识,默认false,对应bean的属性 abstractprivate boolean abstractFlag = false;// 是否延迟加载,对应bean的属性 lazy-initprivate boolean lazyInit = false;// 是否自动注入模式,对应bean的属性autowireprivate int autowireMode = AUTOWIRE_NO;
// 依赖检查,spring3以后弃用这个属性private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// 用来表示一个bean的实例化,依赖另一个bean实例化,对应bean的属性depend-onprivate String[] dependsOn;
// autowire-candidate属性设置为false,这样容器在查找自动装配对象的时候,将不会考虑该bean,即不会考虑该bean作为其他bean的自动装配候选者private boolean autowireCandidate = true;
// 当自动装配出现多个bean,如果primary为true,则改bean作为首席候选者private boolean primary = false;
// 用于记录 Qualifier 对应子元素 qualifierprivate final Map<String, AutowireCandidateQualifier> qualifiers =new LinkedHashMap<String, AutowireCandidateQualifier>(0);private boolean nonPublicAccessAllowed = true;private boolean lenientConstructorResolution = true;//记录构造函数注入属性,对应属性值 constructor-argprivate ConstructorArgumentValues ArgumentValues;
// 普通属性集合private MutablePropertyValues propertyValues;
// 记录 lookup-method和replace-method属性值private MethodOverrides methodOverrides = new MethodOverrides();private String factoryBeanName;private String factoryMethodName;
// 初始化方法 对应属性 init-methodprivate String initMethodName;
// 销毁方法 对应属性 destroy-method
private String destroyMethodName;
// 是否执行 init-method 程序设置private boolean enforceInitMethod = true;
// 是否执行 destroy-method 程序设置private boolean enforceDestroyMethod = true;// 使用用户自定义而不是应用程序本身定义的,创建AOP时候为trueprivate boolean synthetic = false;private int role = BeanDefinition.ROLE_APPLICATION;private String description;
// 这个bean定义的资源private Resource resource;

解析完成以后,会将所有的xml属性值封装至对象 GenericBeanDefinition中,然后会进行注册。

针对以下代码进行分析:

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())

// 解析完以后,BeanDefinition对象就注册到了BeanDefinitionRegisty集合中去了。将beanName作为Key,BeanDefinition作为value。

/*** 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.// 注册所有的bean的别名String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}}

继续深入解析:

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

@Overridepublic 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是否与工厂方法共存,或者对应的方法根本不存在
                ((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Validation of bean definition failed", ex);}}BeanDefinition oldBeanDefinition;oldBeanDefinition = this.beanDefinitionMap.get(beanName);if (oldBeanDefinition != null) {// 对于已经注册过的bean,如果不允许覆盖,则直接抛出异常if (!isAllowBeanDefinitionOverriding()) {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_INFRASTRUCTUREif (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 + "]");}}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<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// 注册beanDefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);// 记录所有的beanNamesthis.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;}if (oldBeanDefinition != null || containsSingleton(beanName)) {// 重置beanName所有的对应的缓存
            resetBeanDefinition(beanName);}}

注册完成,通知所有的监听事件:

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

这里是spring留给子类进行扩展的。

转载于:https://www.cnblogs.com/histlyb/p/8977554.html

spring IOC 之篇三:默认标签的解析相关推荐

  1. Spring默认标签的解析

    2019独角兽企业重金招聘Python工程师标准>>> Spring中的标签包括默认标签和自定义标签两种.默认标签的解析是在parseDefaultElement函数中进行的,分别对 ...

  2. IoC容器篇(三)——依赖(二)

    目录 依赖 2.依赖与配置细节 3.使用depends-on 4.怠惰初始化beans 翻译源:Spring官方文档 依赖 2.依赖与配置细节 直接数值 <property>元素的valu ...

  3. spring源码深度解析— IOC 之 默认标签解析(下)

    默认标签中的自定义标签解析 注册解析的BeanDefinition 通过beanName注册BeanDefinition 通过别名注册BeanDefinition alias标签的解析 import标 ...

  4. java基础巩固-宇宙第一AiYWM:为了维持生计,Spring全家桶_Part1-3(学学Spring源码呗:默认的标签和自定义标签是咋解析的)~整起

    Part3:上一次说到了Spring的DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions(Element root, BeanDefi ...

  5. 【死磕 Spring】----- IOC 之解析 bean 标签:解析自定义标签

    前面四篇文章都是分析 Bean 默认标签的解析过程,包括基本属性.六个子元素(meta.lookup-method.replaced-method.constructor-arg.property.q ...

  6. Spring IOC原理 Bean标签解析和Definition封装

    以下源码版本是 Spring 5.2.x IOC Inversion of Control 控制反转,关键实现是DI Dependency Injection,就必然涉及到有一个容器保存系统中所有托管 ...

  7. spring中默认标签Bean标签解析一

    在Spring种有两种标签,一种是默认标签,另一种是自定义标签.对两种标签的用法和解析方式存在着很大的不同. 首先分析的是默认标签的解析过程. 解析标签的入口代码 protected void par ...

  8. Spring源码解析:自定义标签的解析过程

    2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...

  9. 修改meta标签 查看源码没效果怎么办_Spring 源码学习(三)-自定义标签

    又来填坑啦,上一篇讲完默认标签的解析,这篇笔记记录一下自定义标签的解析吧. 我们知道,Spring 源码的核心模块是 Spring-core 和 Spring-beans,在此基础上衍生出其他模块,例 ...

最新文章

  1. 生成器表达式 内置函数
  2. java ssm 分页_SSM实现简单后台分页
  3. googleearthpro打开没有地球_嫦娥五号成功着陆地球!为何嫦娥五号返回时会燃烧,升空却不会?...
  4. linux设备树sysfs,迅为-iMX6开发板-设备树内核-sys方式控制GPIO
  5. Bootstrap教程:[4]栅格系统详解
  6. 数据库中的左连接(left join)和右连接(right join)区别
  7. php 网址尾部带斜杠和不带区别,URL中带斜杠和不带斜杠的区别 | 米莱SEO博客
  8. mysql数据库编程第六章试题_2016年计算机二级MySQL数据库试题及答案
  9. 基于51单片机的电容电感电阻RLC测量仪protues仿真
  10. vs code 代码格式化整理
  11. 铁道部新客票系统设计
  12. 设计/前端 关于AE动画/特效web实现的四种方法
  13. 小结一篇-(秀我工作一年)
  14. 2022款联想小新air15和联想小新pro14哪个好
  15. 在未提供官方驱动的Windows平板上安装Win10且完美驱动的解决方案
  16. bean是什么,bean和javabean
  17. 10款响应式自适应网站模板(一)
  18. 《DeepLung: Deep 3D Dual Path Nets for Automated Pulmonary Nodule Detection and Classification》网络模型解读
  19. 黑盒测试方法四(正交实验法)
  20. 源码中的modCount是什么?有什么作用

热门文章

  1. step5 . day4 网络编程 基于UDP协议的网络编程流程及API
  2. C#读取资源文件的两种方法及保存资源文件到本地
  3. DRF (Django REST framework) 框架介绍(3)
  4. 【Flask】sqlalchemy 排序
  5. maven 指定jdk版本和编译版本.
  6. win10 EFI装ubuntu14.04双系统 及初始配置
  7. 快速开发框架,及库存管理系统,基于easyui框架和C#语言MVC、EntityFrameWork、T4模板技术。...
  8. 性能测试培训:定位jvm耗时函数
  9. 详细回复某个CSDN网友,对我的文章和技术实力以及CSDN的吐槽
  10. 大数据在2017年发展的8个预测