您的位置:首页 > 编程语言 > Java开发

Spring源码解析(2)之默认标签的解析(二)

2017-12-27 11:01 549 查看
首先感谢 《Spring源码深度解析》郝佳,让我对spring源码有了更深的理解,本篇文章主要是对《Spring源码深度解析》解读的笔记以及自己对书本解读后的理解,本篇文章是对上面一篇Spring源码解析(2)之默认标签的解析(一)的衔接。

⑥:解析子元素constructor-arg

      constructor-arg的使用:
<bean id="car" class="zhuojing.spring.beans.Car">

          <constructor-arg value="Audi" index="0"></constructor-arg>

            <constructor-arg value="Shanghai" index="1"></constructor-arg>

            <constructor-arg value="300000" type="java.lang.Double"></constructor-arg>

       </bean>

       对于constructor-arg 标签的解析spring是通过parseConstructorArgElements函数来实现的。源码如下

     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) {
//提取index属性
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
//提取 type 属性
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
//提取 name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//存在index属性
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));
//解析ele对应的属性元素
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));
<
4000
span style="color:#ff0000;">//不允许重复指定相同参数
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 {
//没有index 属性则忽略去属性,自动寻找
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();
}
}
}        以上parseConstructorArgElement 方法的流程步骤为:
如果存在index属性

  ①:解析constructor-arg 的子元素
②:使用ConstructorArgumentValueHolder 类型来封装解析出来的元素
③:将type、name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前BeanDefinition的constructorArgumentValues的indexedArgumentValuess属性中
如果存在index属性
如果存在index属性

  ①:解析constructor-arg 的子元素
②:使用ConstructorArgumentValueHolder 类型来封装解析出来的元素
③:将type、name和index属性一并封装在ConstructorArgumentValues.ValueHolder类型中并添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中

        接着进一步了解构造函数配置中的子元素的过程

  public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";

// 一个属性只能对应一种类型: ref, value, list, etc.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//对应description 或 meta 不处理
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
// Child element is what we're looking for.
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
//解析constructor-arg上的ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
//解析constructor-arg 上的value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
/**
*在constructor-arg 上不会存在这两种情况
* 1、同时既有ref属性又有value属性
* 2、存在ref属性或者value属性且又有子元素
*/
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
//ref属性的处理,使用RuntimeBeanReference 封装对应的ref 名称
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
//value 属性的处理,使用TypedStringvalue封装
else if (hasValueAttribute) {
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
else if (subElement != null) {
//解析子元素
return parsePropertySubElement(subElement, bd);
}
else {
// 既没有ref属性也没有value属性,也没有子元素
error(elementName + " must specify a ref or value", ele);
return null;
}
}        解构造函数配置中的子元素的步骤流程

        ①:略过description 或者meta
②:提取constructor-arg 上的ref和value属性,以便于根据规则验证正确性,其规则在constructor-arg上不存在一下情况
  同时既有ref属性又有value属性

          存在ref属性或者value属性且又有子元素

        

        解析 constructor-arg下的子元素(map、list等)
       public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
return parsePropertySubElement(ele, bd, null);
}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// 解析local
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
//解析parent
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean', 'local' or 'parent' is required for <ref> element", ele);
return null;
}
}
}
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
//解析idref 元素
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
return parseIdRefElement(ele);
}
//解析value 子元素
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
return parseValueElement(ele, defaultValueType);
}
//对 null 子元素的解析
else if (nodeNameEquals(ele, NULL_ELEMENT)) {
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
//解析array 子元素
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
return parseArrayElement(ele, bd);
}
//解析list
else if (nodeNameEquals(ele, LIST_ELEMENT)) {
return parseListElement(ele, bd);
}
//解析set 子元素
else if (nodeNameEquals(ele, SET_ELEMENT)) {
return parseSetElement(ele, bd);
}
//解析map 子元素
else if (nodeNameEquals(ele, MAP_ELEMENT)) {
return parseMapElement(ele, bd);
}
//解析props 子元素
else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
return parsePropsElement(ele);
}
else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
解析array 子元素源码(其他解析list、set等子元素跟解析array大同小异,这边只举例array,都是用ManagedArray 类封装下子元素,然后进行解析,最后将ManagedArray 返回):
  public Object parseArrayElement(Element arrayEle, BeanDefinition bd) {
//获取子元素类型
String elementType = arrayEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
//获取子元素的孩子列表
NodeList nl = arrayEle.getChildNodes();
//根据子元素的类型声明ManagedArray
ManagedArray target = new ManagedArray(elementType, nl.getLength());
//将子元素转换成Object,存放在ManagedArray,
target.setSource(extractSource(arrayEle));
//保存子元素的类型
target.setElementTypeName(elementType);
//子元素是否存在merge属性
target.setMergeEnabled(parseMergeAttribute(arrayEle));
//解析子元素中的孩子节点(孩子节点为Collection类型)
parseCollectionElements(nl, target, bd, elementType);
return target;
}
protected void parseCollectionElements(
NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
//遍历子元素的孩子节点
for (int i = 0; i < elementNodes.getLength(); i++) {
Node node = elementNodes.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
//很具子元素的类型,解析孩子节点,并存放在ManagedArray中
target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
}
}
}
      ⑦:解析子元素property

             解析property在parsePropertyElements 方法中
public void parsePropertyElements(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, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
//获取name属性值
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
//不允许对此对同一个属性配置
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
//解析子元素(根据constructor-arg解析子元素方法一样)
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
         解析Property 子元素的方法中将property子元素的数据封装到PropertyValue进行封装,并记录在BeanDefinition中的propertyValue属性中

⑧:解析子元素qualifier
     对于qualifier 元素的获取,我们更多的是注解的形式,在Spring框架中进行自动注入。当找不到匹配的Bean时,Spring 容器将抛出BeanCreateException异常,
    并指出必须至少拥有一个匹配的Bean
    Spring允许我们通过Qualifier 指定注入Bean的名称,这样歧义就消除了

2、AbstractBeanDefinition 属性

      以上完成了对XML文档到GenericBeanDefinition 的转换,也就是XML的所有属性都是存放在GenericBeanDefinition 的实例中

GenericBeanDefinition 只是一个子类实现,二大部分属性都是保存在AbstractBeanDefinition 

     AbstractBeanDefinition 类源码

@SuppressWarnings("serial")
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
//略过常量
//bean的作用范围,对应bean 属性scope
private String scope = SCOPE_DEFAULT;
//是否是抽象
private boolean abstractFlag = false;
//是否懒加载
private boolean lazyInit = false;
//自动注入
private int autowireMode = AUTOWIRE_NO;
//依赖检查,Spring3.0后启用这个属性
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
//用来表示一个bean 的实例化依靠另一个bean先实例化,对应属性depend-on
private String[] dependsOn;
//对用bean属性的autowire-candidate
private boolean autowireCandidate = true;
//自动装配是当出现多个bean候选者是,将作为首选者,对用bean属性primary
private boolean primary = false;
//用于记录Qualifier,对应子元素qualifier
private final Map<String, AutowireCandidateQualifier> qualifiers =
new LinkedHashMap<String, AutowireCandidateQualifier>(0);
//运行访问非公开的构造器和方法,程序设置
private boolean nonPublicAccessAllowed = true;
//异常抛出,因为Spring 无法确定定位哪个构造函数
private boolean lenientConstructorResolution = true;
//记录构造函数注入属性,对用bean属性constructor-arg
private ConstructorArgumentValues constructorArgumentValues;
//普通属性集合
private MutablePropertyValues propertyValues;
//方法重新的持有者,记录lookup-method、relaced-method元素
private MethodOverrides methodOverrides = new MethodOverrides();
//对应bean属性 factory-bean
private String factoryBeanName;
//对应bean属性 factory-method
private String factoryMethodName;
//初
e87a
始化方法 对应bean属性的init-method
private String initMethodName;
//销毁方法 对应bean属性destory-method
private String destroyMethodName;
//是否执行destory-method方法
private boolean enforceInitMethod = true;
//是否执行init-method方法
private boolean enforceDestroyMethod = true;
//是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true
private boolean synthetic = false;
//
private int role = BeanDefinition.ROLE_APPLICATION;
//描述信息
private String description;
//bean定义的资源
private Resource resource;
}

  3、解析默认标签中的自定义标签元素
       再次回顾解析标签函数的开始方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析bean标签,bdHolder 包含着bean标签的所有属性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//解析自定义标签元素
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));
}
}       在上面我们用了很大的篇幅在分析BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);这句话,接下来我们就要解析bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);。
       这句代码就是进行自定义标签元素解析的,源码如下

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
这边decorateBeanDefinitionIfRequired的方法中的第三参数是为了使用父类的scope属性,以备子类若没有设置scope时默认使用父类的属性,这里分析是顶层配置,所有传递null
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

BeanDefinitionHolder finalDefinition = definitionHolder;

// 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, BeanDefinition containingBd) {
//获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
//对于非默认标签进行修饰
if (!isDefaultNamespace(namespaceUri)) {
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//根据命名空间找到对应的处理器
if (handler != null) {
//进行修饰
return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
}
else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
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;
}
       以上代码步骤:首先获取属性或者元素的命名空间,以此来判断元素或者属性是否适用于自定义标签的解析条件,找出自定义类型所对应的NamespaceHandler并进行进一步解析
 4、注册解析的BeanDefinition

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());的解析,源码如下

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) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
以上代码可以看出,解析的beanDefinition 都会被注册到BeanDefinitionRegistry类型的registry,beanDefinition 注册分为通过beanName注册以及通过别名注册
a、通过beanName注册BeanDefinition
    对于beanDefinition 注册,其实就是将beanDefinition 放在map中,使用beam作为key,除此之外Spring还做了其他操作,源码如下(DefaultListableBeanFactory类中)

   @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) {
/*
*注册前的最后一次,这里的校验不同于之前的XML文件检验
*主要是对于AbstractBeanDefinition 属性中的methodOverride是校验
*校验methodOverrides是否与工厂方法并存或者methodOverrides对应的方法根本不存在
*/
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//因为beanDefinitionMap是全局变量,这里定会存在并发的访问的情况
synchronized (this.beanDefinitionMap) {
BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
//处理已经注册的beanName情况
if (oldBeanDefinition != null) {
//如果对应的BeanName 已经注册且在配置了bean不允许被覆盖,则抛出异常
if (!this.allowBeanDefinitionOverriding) {
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 (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
//记录beanName
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
//将beanDefinition加入到map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//重置所有beanName对应的缓存
resetBeanDefinition(beanName);
}
    以上对于bean的注册处理主要有以下几个步骤
    ①:对AbstractBeanDefinition 的校验,但这边校验跟解析XML文件时候校验不同,解析XML校验是针对XML格式校验,而这边的校验是针对AbstractBeanDefinition的methodOverride是属性的
    ②:对于已经注册的bean,且设置了不允许bean的覆盖,则会抛出异常,否则会直接覆盖
    ③:加入map 缓存
          ④:重置beanName对应的缓存

b、通过别名注册BeanDefinition
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
//如果beanName 与alias 相同的话不记录alias,并删除对应的alias
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
//如果alias 不允许被覆盖则抛出异常
if (!allowAliasOverriding()) {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null && !registeredName.equals(name)) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
//当A -> B存在时,若再次出现A -> C -> B
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}     注册别名的代码步骤
   ①:alias与beanName 相同情况处理,若alias与beanName并名称相同则不需要处理并删除掉原有的alias
   ②:alias覆盖处理,若aliasName 已经使用并已经指向了另一beanName则需要用户的设置进行处理
   ③:alias 循环检查。当A -> B存在时,若再次出现A ->C->B时候则会抛出异常
   ④:注册alias

5、通知监听器解析及注册完成
通过getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));完成通知监听器解析及注册完成
6、alias 标签的解析   在对于bean进行定义是,除了使用id属性来指定名称之外,为了提供读个名称,可以使用alias 标签来指定。而所有的这些名称都是

指向同一个bean。在某些情况提供别名非常有用,比如为了让应用的每一个组件能够更容易的对公共组件进行引用
使用方法:

<bean id="testBean" class="com.test"/>
<alias name="testBean" alias="testBean,testBean2" />
alias标签解析的源码如下

protected void processAliasRegistration(Element ele) {
//获取beanName
String name = ele.getAttribute(NAME_ATTRIBUTE);
//获取alias
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 {
//注册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));
}
} 从以上代码可以看出alias解析跟之前bean解析大同小异,都是将别名与beanName组成一队注册至registry中
7、Import 标签的解析
Import标签主要是对配置文件进行分模块的作用
使用方法:
<import resource="customerContext.xml"/>
在配置文件中可以使用import的方法导入有模块配置文件,以后若有新模块的加入,那就可以简单修改这个文件了。这样易于管理
源码如下
protected void importBeanDefinitionResource(Element ele) {
//获取resource属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
//如果不存在resource 属性则不做任何处理
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}

// 解析系统属性,格式如. "${user.dir}"
location = environment.resolveRequiredPlaceholders(location);

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

// 判定location 是决定URI还是相对URL
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*:"
}

// 如果是绝对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 存在多个子实现类,如VfsResource、FileSystemResource
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
//如果解析不成功,则使用默认的解析器ResourcePatternResolver进行解析
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);
}
}
//解析后进行监听激活处理
Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
} 以上解析Import 标签代码步骤
①:获取resource 属性所表示的路径
②:解析路径中的系统属性,格式如“${user.dir}”
③:判定location 是绝对另还是相对路径
④:如果是绝对路径则递归调用bean的解析过程,进行另一次的解析
⑤:如果是相对路径则计算出绝对路径并进行解析
⑥:通知监听器,解析完成
 8、嵌入式beans标签的解析
嵌入式beans标签的解析非常类似于import 标签所提供的功能,这个和单独的配置文件并没有太大的差别,无非是递归调用beans的解析过程,跟以上步骤一样

   9、默认标签解析流程总结(bean标签,其他标签大同小异)
①:BeanDefinitionParserDelegate 类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder 实例,返回的BeanDefinitionHolder 实例中包含bean标签的各中属性
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

        a:提取元素中的id和name 属性

        b:进一步解析其他所有属性并统一封装到GenericBeanDefinition 类型的实例中

        c:如果检测到bean没有beanName,那么会使用默认的规则生成beanName

        d:将获取到的信息封装到BeanDefinitionHolder
②:解析子节点的自定义属性:bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)

        a:获取属性或者元素的命名空间,根据属性或者元素的命名空间来判断是否是自定义标签,然后进行解析
③:注册解析的BeanDefinition(map缓存的形式)

        a:通过beanName注册BeanDefinition(不允许bean的覆盖)

        b:通过别名注册BeanDefinitio
④:通知监听器解析及注册完成
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: