• 四种标签

在spring的配置文件中存在四种基本的标签分别是:beans,bean,import,alias

四种标签的功能:

beans:定义一个单独的应用配置(测试配置,开发配置等),在服务器部署的时候可以选择部署哪一个应用配置

bean:最基本的定义一个对象

import:导入配置文件

alias:为定义的bean取别名

  • 解析的入口

spring先用sax解析器完成对xml配置文件的解析,将xml中的标签在内存中创造成一颗文档树。

protected void doRegisterBeanDefinitions(Element root) {

        BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { //文档以<beans>标签作为根标签则进行以下的判断
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);//获取beans标签下的profile属性 判断profile属性
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);//将profile属性的值按照分隔符分隔成字符串数组if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { //当所给定的profile属性的值全部都没激活则不用继续加载接下来的xml
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
} preProcessXml(root); //用户如果重写这个方法表示在加载bean,inport,beans,alias等标签前应该执行的操作
parseBeanDefinitions(root, this.delegate); //加载bean,inport,beans,alias等标签
postProcessXml(root);//用户如果重写这个方法表示在加载bean,inport,beans,alias等标签后应该执行的操作 this.delegate = parent;
}

上述操作主要是对<beans profiles=""><beans/>标签进行操作,在xml文件中可能存在多个beans标签,每一个beans标签中可以定义一个项目的配置profiles可以为这个配置命名,spring框架会根据profiles的激活情况加载对应的配置。

激活profiles的几种方法 :
 作为SpringMVC中的DispatcherServlet的初始化参数
 作为Web 应用上下文中的初始化参数
 作为JNDI的入口
 作为环境变量 (Windows为服务器时windows中添加环境变量)
 作为虚拟机的系统参数(linux为服务器时,在~/.bash_profile里最后一行增加 export SPRING_PROFILES_ACTIVE=dev)
 使用@AtivceProfile来进行激活

  • bean标签的解析1-beanname的解析

下面解析根标签

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>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
} //将多个name存储到aliases 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");
}
} // 如果bean标签没有id属性则将第一个name的值赋给bean name否则beanname的值为id if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele); //判断bean name有没有被加载过
} AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); //解析<bean>里面的标签
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition); //依据类名生成一个独一无二的名字 如 classname#0 String beanClassName = beanDefinition.getBeanClassName(); //真正的类名
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
} //如果真正的类名之前没有被注册到aliases或者register则注册进去
}
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);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} return null;
}

上面的代码主要是获取beanname

1.有id属性取id为beanname

2有那么属性取第一个name属性为beanname

3有外部bean(即当前被创造的bean只是另外一个bean的属性)如果有parent取parentbean的beanname加上$child加上系统自动生成的hashcode,如果没有parent但是有factorybeanname取factorybeanname加上$create加系统自动生成的hashcode

4.无外部bean,再判断是否有parentbean如果有按照已生成的数量命名如parentbeanname$child#0,parentbeanname$child#1........;如果没有parentbean但是有factorybeanname按照已生成的数量命名factorybeanname$create#0,factorybeanname$create#1......

  • bean标签的解析2-attribute的解析

  

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
} if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
} String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire)); String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
} String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
} if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
} if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
if (!"".equals(initMethodName)) {
bd.setInitMethodName(initMethodName);
}
}
else {
if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
} if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else {
if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
} if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
} return bd;
}

上述代码包含了对<bean> 标签中属性值得解析,属性值包括:scope,singleton,abstract,lazy-init,autowire,dependcy-check,depends-on,autowire-candidate,primary,init-method,destroy-method,factory-method,factory-bean

接下来是对<bean>标签内的元素标签解析。具体的解析步骤类似:将相应类型的节点的元素值取出放到beandefinition中

       parseMetaElements(ele, bd);//解析<meta key='' value=''> 元数据标签, 将键值对放入attributeAccessor
parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //动态代理生成类
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); //解析<constructor-arg index='' type='' name=''/> 属性
parsePropertyElements(ele, bd); //解析<property name=''/> 属性
parseQualifierElements(ele, bd); //解析<qualifier type='' value=''><attribute key='' vaule='' /><qualifier>
  • meta标签的解析
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
attributeAccessor.addMetadataAttribute(attribute);
}
}
}

将meta标签的key和value属性放到beandefinition

  • Lookup-method标签的解析
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) {
Element ele = (Element) node;
String methodName = ele.getAttribute(NAME_ATTRIBUTE);
String beanRef = ele.getAttribute(BEAN_ELEMENT);
LookupOverride override = new LookupOverride(methodName, beanRef);
override.setSource(extractSource(ele));
overrides.addOverride(override);
}
}
}

将lookup-mathod标签的name和bean属性放到beandefinition

  • replace-method的解析
public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) {
Element replacedMethodEle = (Element) node;
String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE);
String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE);
ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
// Look for arg-type match elements.
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
for (Element argTypeEle : argTypeEles) {
String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
if (StringUtils.hasText(match)) {
replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(extractSource(replacedMethodEle));
overrides.addOverride(replaceOverride);
}
}
}

将replace-mathod标签的name和bean属性放到beandefinition

  • constructor-arg的解析

public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
parseConstructorArgElement((Element) node, bd);
}
}
}
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
if (index < 0) {
error("'index' cannot be lower than 0", ele);
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry(index));
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
}
else {
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
}
finally {
this.parseState.pop();
}
}
}
catch (NumberFormatException ex) {
error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
}
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry());
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}

上述代码将constructor标签中的子标签和属性值进行解析

  • 解析property标签

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
parseQualifierElement((Element) node, bd);
}
}
}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
if (!StringUtils.hasLength(typeName)) {
error("Tag 'qualifier' must have a 'type' attribute", ele);
return;
}
this.parseState.push(new QualifierEntry(typeName));
try {
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
qualifier.setSource(extractSource(ele));
String value = ele.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(value)) {
qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
}
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
Element attributeEle = (Element) node;
String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
attribute.setSource(extractSource(attributeEle));
qualifier.addMetadataAttribute(attribute);
}
else {
error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
return;
}
}
}
bd.addQualifier(qualifier);
}
finally {
this.parseState.pop();
}
}

上述代码遍历property标签完成对标签元素的提取。

  • 解析qualifier标签的解析

public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
parseQualifierElement((Element) node, bd);
}
}
}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
String typeName = ele.getAttribute(TYPE_ATTRIBUTE);
if (!StringUtils.hasLength(typeName)) {
error("Tag 'qualifier' must have a 'type' attribute", ele);
return;
}
this.parseState.push(new QualifierEntry(typeName));
try {
AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);
qualifier.setSource(extractSource(ele));
String value = ele.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(value)) {
qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
}
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ATTRIBUTE_ELEMENT)) {
Element attributeEle = (Element) node;
String attributeName = attributeEle.getAttribute(KEY_ATTRIBUTE);
String attributeValue = attributeEle.getAttribute(VALUE_ATTRIBUTE);
if (StringUtils.hasLength(attributeName) && StringUtils.hasLength(attributeValue)) {
BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
attribute.setSource(extractSource(attributeEle));
qualifier.addMetadataAttribute(attribute);
}
else {
error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
return;
}
}
}
bd.addQualifier(qualifier);
}
finally {
this.parseState.pop();
}
}

上述代码完成对qualifier元素的提取

spring原理之四种基本标签的解析的更多相关文章

  1. Spring 系列教程之默认标签的解析

    Spring 系列教程之默认标签的解析 之前提到过 Spring 中的标签包括默认标签和自定义标签两种,而两种标签的用法以及解析方式存在着很大的不同,本章节重点带领读者详细分析默认标签的解析过程. 默 ...

  2. Spring 系列教程之自定义标签的解析

    Spring 系列教程之自定义标签的解析 在之前的章节中,我们提到了在 Spring 中存在默认标签与自定义标签两种,而在上一章节中我们分析了 Spring 中对默认标签的解析过程,相信大家一定已经有 ...

  3. Spring框架之AOP源码完全解析

    Spring框架之AOP源码完全解析 Spring可以说是Java企业开发里最重要的技术.Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Orie ...

  4. Spring源码学习(2)——默认标签的解析

    上一篇随笔说到Spring对于默认标签和自定义标签的解析方法是不同的,这里详细看一下Spring对于默认标签的解析. private void parseDefaultElement(Element ...

  5. 【Spring源码深度解析学习系列】复杂标签属性解析(四)

    一.创建用于属性承载的BeanDefinition BeanDefiniton是一个接口,在Spring中存在三种实现:RootBeanDefinition.ChildBeanDefinition.G ...

  6. Spring源码分析(九)解析默认标签中的自定义标签元素

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 到这里我们已经完成了分析默认标签的解析与提取过程,或许涉及的内容太多,我 ...

  7. Spring源码分析(七)bean标签的解析及注册

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 在上一篇中提到过Spring中的标签包括默认标签和自定义标签两种,而两种 ...

  8. spring源码学习之默认标签的解析(二)

    这个是接着上一篇来写,主要是这章内容比较多,还是分开来写吧! 一.AbstractBeanDefinition属性介绍 XML中的所有的属性都可以在GenericBeanDefinition中找到对应 ...

  9. spring源码学习之默认标签的解析(一)

    继续spring源码的学习之路,现在越来越觉得这个真的很枯燥的,而且我觉得要是自己来看源码,真的看不下去,不是没有耐心,而是真的没有头绪,我觉得结合着书来看,还是很有必要的,最起码大致的流程是能够捋清 ...

随机推荐

  1. 程序员的自我修养系列(一):优雅的代码管理工具之GitHub

    1.导言 代码管理是程序员经常遇到一个问题,很多童鞋将代码保存到本地硬盘,此种方法管理混乱,也存在代码丢失的风险,且版本无法控制,因此养成良好的代码管理习惯是程序员的必修课.在众多代码管理工具中笔者在 ...

  2. Linux(ubuntu) 一行代码搞定查看文件目录

    ls 命令:• ls 是英文单词 list 的简写,其功能为列出目录的内容,是用户最常用的命令之一,类似于 DOS 下的 dir 命令 ls命令之后加各种参数的作用: ls -a 显示指定目录下所有子 ...

  3. Github使用总结(添加ssh-key,新建仓库,添加协作者) 转

    http://jingyan.baidu.com/article/ab0b5630936ab6c15afa7d1c.html https://help.github.com/articles/gene ...

  4. 类,接口,final

    继承extends 子类实例化过程: 子类中所有的构造方法默认都会访问父类中空参的构造方法 因为每一个子类的构造方法的提议行都有一条默认的语句super(); this super final修饰类, ...

  5. USB通信协议深入理解

    0. 基本概念 一个[传输](控制.批量.中断.等时):由多个[事务]组成: 一个[事务](IN.OUT.SETUP):由一多个[Packet]组成. USB数据在[主机软件]与[USB设备特定的端点 ...

  6. 5. this关键字

    一.this关键字概述 1. this作为对象的引用,它总是指向调用该方法的对象 2. this的最大作用:让类中的一个方法访问该类中的另一个方法或实例变量 二.this关键字的两种用法 1. 在方法 ...

  7. day77_10_24分页器

    一.偏移分页器. 在偏移分页器中,limit代表的是一次性显示的条数,而offset代表的是他基于开头的偏移量. from rest_framework.pagination import Limit ...

  8. logback基本使用

    logback基本使用 参考 Java日志框架:logback详解 # logback官网 http://logback.qos.ch/manual/index.html 使用步骤 构建logback ...

  9. CME Futures & Options Order Book

    http://algo-logic.com/futures-options-orderbook Algo-Logic Systems’ Futures & Options (F&O) ...

  10. Luogu P5363 [SDOI2019]移动金币

    话说这题放在智推里好久了的说,再不写掉对不起自己233 首先你要知道一个叫做阶梯Nim的东西,具体的可以看这篇博客 那么我们发现这和这道题的关系就很明显了,我们把两个金币之间的距离看作阶梯Nim的每一 ...