标签解析
在Spring的XML配置里面有两大类声明,一个是默认的如<bean id=”test” class=”test.TestBean” />,另一类就是自定义的如<tx:annotation-driven />,两种标签的解析方式差异是非常大的。parseBeanDefinitions方法就是用来处理使用哪种方式解析标签,判断是否默认命名空间还是自定义命名空间的办法是使用node.getNamespaceURI()获取命名空间,并与Spring中固定的命名空间http://www.springframework.org/schema/beans 进行比对,如果一致则认为是默认命名空间否则就认为是自定义命名空间解析
默认命名空间解析
Spring将默认标签解析分为4种类型,分别为import,alias,bean,和beans标签
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// import标签解析
importBeanDefinitionResource(ele);
} else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// alias标签解析
processAliasRegistration(ele);
} else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// bean标签解析
processBeanDefinition(ele, delegate);
} else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
// beans标签解析 递归方式
doRegisterBeanDefinitions(ele);
}
}
bean标签解析
在4种标签中对bean标签的解析最为复杂也最为重要,所以我们从此标签开始深入分析,如果能理解此标签的解析过程,其他标签的解析自然会迎刃而解,在上一篇博客介绍了BeanDefinitionParserDelegate(bean标签解析代理对象)的创建过程,接下来我们将详细介绍使用BeanDefinitionParserDelegate对bean标签的解析过程,bean标签解析的方法的入口为processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 01.委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 02.当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 03.解析完成后需要对解析后的bdHolder进行注册,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
}
// 04.最后发出响应事件,通知相关监听器这个bean已经被加载
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这个方法可以分为四个部分
01.委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析
02.当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析
03.解析完成后需要对解析后的bdHolder进行注册,注册操作委托给了BeanDefinitionReaderUtils的registerBeanDefinition方法
04.最后发出响应事件,通知相关监听器这个bean已经被加载
parseBeanDefinitionElement(Element ele)
通过该方法返回BeanDefinitionHolder类型的实例bdHolder,经过这个方法后bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class, name, id, alisa等之类的属性
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取Bean标签的ID属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取Bean标签的Name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
// 将name属性的值通过,; 进行分割 转为字符串数字(即在配置文件中如配置多个name 在此做处理)
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 如果ID为空 使用配置的第一个name属性作为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) {
// 校验beanName和aliases的唯一性
// 内部核心为使用usedNames集合保存所有已经使用了的beanName和alisa
checkNameUniqueness(beanName, aliases, ele);
}
// 进一步解析其他所有属性到GenericBeanDefinition对象中
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 如果bean没有指定beanName 那么使用默认规则为此Bean生成beanName
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = 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;
}
该方法主要完成三个功能,第一部分是处理id,alias等标识相关的东西,第二部分是核心的标签解析,标签解析功能主要是在重载函数parseBeanDefinitionElement(ele, beanName, containingBean)方法中完成,第三部分是对beanName的处理,接下来我们重点分析第二部分内容
parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 获取Bean标签的class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 获取Bean标签的parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建用于承载属性的AbstractBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 获取bean标签各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 解析description标签
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析meta标签
parseMetaElements(ele, bd);
// 解析lookup-method标签
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析constructor-arg标签
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;
}
createBeanDefinition(@Nullable String className, @Nullable String parentName) 创建用于承载属性的GenericBeanDefinition
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());
}
public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
// parentName可能为空
bd.setParentName(parentName);
if (className != null) {
// 如果classLoader不为空
// 则使用传入的classLoader同一虚拟机加载类对象 否则只记录classLoader
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
} else {
bd.setBeanClassName(className);
}
}
return bd;
}
parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) 解析Bean各种属性到GenericBeanDefinition对象中
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
// 如果配置了singleton属性抛出异常 该属性已经废弃
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
// 获取Bean标签的scope属性
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
} else if (containingBean != null) {
// 如果有内部类 使用内部类的scope属性
bd.setScope(containingBean.getScope());
}
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
// 获取Bean标签的abstract属性
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 获取Bean标签的lazy-init属性
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// 获取Bean标签的autowire属性
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// 获取Bean标签的depends-on属性
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// 获取Bean标签的autowire-candidate属性
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));
}
// 获取Bean标签的primary属性
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
// 获取Bean标签的init-method属性
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
bd.setInitMethodName(initMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 获取Bean标签的destroy-method属性
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);
}
// 获取Bean标签的factory-method属性
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
// 获取Bean标签的factory-bean属性
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) 解析meta标签到GenericBeanDefinition中
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)) {
// 解析META标签
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);
}
}
}
parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) 解析lookup-method标签到GenericBeanDefinition中
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)) {
// 解析lookup-method标签
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-method通常称为获取器注入,它是一种特殊的方法注入,它是把一个方法声明为返回某种类型的bean,而实际要返回的bean是在配置文件里面配置的,可用在设计可插拔的功能上,降低程序耦合度,下面介绍一个lookup-method的demo
新建歌手方法抽象类Singer,声明抽象方法sing
package org.springframework.roberto._05_lookup_method;
public abstract class Singer {
protected abstract void sing();
}
创建歌手陈奕迅继承该抽象类,实现sing方法
package org.springframework.roberto._05_lookup_method;
public class EasonChen extends Singer{
@Override
public void sing() {
System.out.println("十年");
}
}
创建演唱会类,选择哪个歌手开演唱会
package org.springframework.roberto._05_lookup_method;
public abstract class VocalConcert {
public void sing(){
this.getSinger().sing();
}
public abstract Singer getSinger();
}
配置文件声明如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans>
<bean id="vocalConcert" class="org.springframework.roberto._05_lookup_method.VocalConcert">
<lookup-method name="getSinger" bean="easonChen" />
</bean>
<bean id="easonChen" class="org.springframework.roberto._05_lookup_method.EasonChen" />
</beans>
</beans>
新建测试类,测试演唱会功能
package org.springframework.roberto;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.roberto._05_lookup_method.VocalConcert;
@SuppressWarnings("all")
public class _05_LookupMethodTest {
@Test
public void testLookupMethod() {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("05.lookup_method.xml"));
VocalConcert vocalConcert = (VocalConcert) beanFactory.getBean("vocalConcert");
vocalConcert.sing();
}
}
测试结果输出十年,这里只是调用了一个没有实现的抽象方法就完成了执行,其原理在于将EasonChen作为getSinger方法的返回值,这么做有利于程序的拓展。比如下次换张学友来开演唱会的时候,我们只需要把陈奕迅换成张学友即可,不用改动VocalConcert的任何代码
parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) 解析replaced-method标签到GenericBeanDefinition中
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)) {
// 解析replaced-method标签
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);
}
}
}
replaced-method可以在运行时用新的方法替换掉旧的方法,如上面的例子假设现在举办方要陈奕迅演唱粤语版的十年(明年今日),如果我们直接去改EasonChen中的方法其实是不合理的,我们新建一个类叫EasonChenBack实现Spring的MethodReplacer方法,并修改配置即可替换掉原来的方法
package org.springframework.roberto._06_replace_method;
import org.springframework.beans.factory.support.MethodReplacer;
import java.lang.reflect.Method;
public class EasonChenBack implements MethodReplacer{
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("明年今日");
return null;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beans>
<bean id="vocalConcert" class="org.springframework.roberto._05_lookup_method.VocalConcert">
<lookup-method name="getSinger" bean="easonChen" />
</bean>
<bean id="easonChen" class="org.springframework.roberto._05_lookup_method.EasonChen">
<replaced-method name="sing" replacer="easonChenBack" />
</bean>
<bean id="easonChenBack" class="org.springframework.roberto._06_replace_method.EasonChenBack"/>
</beans>
</beans>
运行结果输出十年今日,也就是原来EasonChen中的sing方法已经被替换掉了
parseConstructorArgElements(Element beanEle, BeanDefinition bd) 解析constructor-arg标签到GenericBeanDefinition中
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)) {
// 解析constructor-arg标签
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);
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));
// 不允许重复指定相同的参数
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 {
// 没有index属性解析
this.parseState.push(new ConstructorArgumentEntry());
// 解析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));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
} finally {
this.parseState.pop();
}
}
}
parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) 该方法用于获取一个属性元素的值,可以是ref value或者list等,如果propertyName设置为null即为构造函数获取值方式
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
// 一个属性只能对应一种子标签 ref value或者list等
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;
}
}
}
// 获取ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
// 获取value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
// 1.同时既有ref属性又有value属性 则报错
// 2.存在ref属性或者value属性且又有子元素 则报错
if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
if (hasRefAttribute) {
// 对ref属性处理
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;
} else if (hasValueAttribute) {
// 对value属性处理
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;
}
}
这里主要流程可以分为五个部分
1.解析出子元素ref,value,list,map等
2.校验是否同时拥有ref属性和value属性 或存在ref属性或者value属性但是又有子元素
3.解析ref属性用RuntimeBeanReference封装
4.解析value属性用TypedStringValue封装
5.使用parsePropertySubElement对子元素进行处理
子元素标签解析
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd) {
return parsePropertySubElement(ele, bd, null);
}
public Object parsePropertySubElement(Element ele, @Nullable BeanDefinition bd, @Nullable String defaultValueType) {
// 判断是否使用默认命名空间
if (!isDefaultNamespace(ele)) {
// 自定义标签解析
return parseNestedCustomElement(ele, bd);
} else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
// bean标签解析
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
} else if (nodeNameEquals(ele, REF_ELEMENT)) {
// ref标签解析
// 获取ref标签bean属性
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// 解析ref标签parent属性
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean' 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;
} else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
// idref标签解析
return parseIdRefElement(ele);
} else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
// value标签解析
return parseValueElement(ele, defaultValueType);
} else if (nodeNameEquals(ele, NULL_ELEMENT)) {
// null标签解析
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
} else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
// array标签解析
return parseArrayElement(ele, bd);
} else if (nodeNameEquals(ele, LIST_ELEMENT)) {
// list标签解析
return parseListElement(ele, bd);
} else if (nodeNameEquals(ele, SET_ELEMENT)) {
// set标签解析
return parseSetElement(ele, bd);
} else if (nodeNameEquals(ele, MAP_ELEMENT)) {
// map标签解析
return parseMapElement(ele, bd);
} else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
// props标签解析
return parsePropsElement(ele);
} else {
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
对property各种子元素处理逻辑请自行分析,不再详述
parsePropertyElements(Element beanEle, BeanDefinition bd) 解析property标签到GenericBeanDefinition中
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)) {
// 解析property标签
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;
}
// 获取属性元素的值
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
// 解析meta标签
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
} finally {
this.parseState.pop();
}
}
parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) 解析qualifier标签到GenericBeanDefinition中
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)) {
// 解析qualifier标签
parseQualifierElement((Element) node, bd);
}
}
}
public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
// 获取type属性
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));
// 获取value属性
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)) {
// 解析attribute标签
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();
}
}
decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder)
当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析,这里有别于自定义类型的解析
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
// 遍历所有属性 查看是否有适用于修饰的属性
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 遍历所有的子节点 判断是否有适用于修饰的子元素
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) {
// 获取自定义标签的命名空间
String namespaceUri = getNamespaceURI(node);
// 对于非默认标签进行装饰
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 根据命名空间找到对应的处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// 进行修饰
BeanDefinitionHolder decorated = handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
} else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
} else {
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
在解析完配置文件后我们已经获取了bean的所有属性,接下来就是对bean的注册了
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// 使用beanName做唯一标识符
String beanName = definitionHolder.getBeanName();
// 注册bean的核心代码
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 为bean注册所有的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
以上代码主要完成两个功能,一是使用beanName注册beanDefinition,二是完成了对别名的注册
使用beanName注册beanDefinition
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 {
// 注册前的最后一次校验,这里的校验不同于XML文件校验
// 主要是对于AbstractBeanDefinition属性中的methodOverrides校验
// 校验methodOverrides是否与工厂方法并存或者methodOverrides对于的方法根本不存在
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
// 获取缓存中的beanDefinition
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
// 如果缓存中存在 判断是否允许覆盖
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()) {
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 (!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 + "]");
}
}
// 如果允许覆盖,保存beanDefinition到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// 判断是否已经开始创建bean
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
// 保存beanDefinition到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 更新已经注册的beanName
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
} else {
// 还没开始创建bean
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
// 重置beanName对应的缓存
resetBeanDefinition(beanName);
}
}
使用beanName注册beanDefinition主要完成了以下几个功能
1.对AbstractBeanDefinition的校验,主要是针对AbstractBeanDefinition的methodOverrides属性的
2.对beanName已经注册的情况的处理,如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖
3.使用beanName作为key,beanDefinition为Value加入beanDefinitionMap存储
4.如果缓存中已经存在,并且该bean为单例模式则清楚beanName对应的缓存
注册别名
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
if (alias.equals(name)) {
// 如果beanName与alias相同的话不记录alias 并删除对应的alias
this.aliasMap.remove(alias);
} else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// 如果别名已经注册过并且指向的name和当前name相同 不做任何处理
return;
}
// 如果alias不允许被覆盖则抛出异常
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
}
}
// 校验循环指向依赖 如A->B B->C C->A则出错
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
}
}
注册别名主要完成了以下工作
1.如果beanName与alias相同的话不记录alias 并删除对应的alias
2.如果别名已经注册过并且指向的name和当前name相同 不做任何处理
3.如果别名已经注册过并且指向的name和当前name不相同 判断是否允许被覆盖
4.校验循环指向依赖 如A->B B->C C->A则出错
fireComponentRegistered(ComponentDefinition componentDefinition)
通过fireComponentRegistered方法进行通知监听器解析及注册完成工作,这里的实现只为扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时,可以通过注册监听器的方式并将处理逻辑写入监听器中,目前Spring中并没有对此事件做任何处理
alias标签解析
Spring提供了<alias name=”testBean” alias=”testBeanAlias” />方式来进行别名的配置,该标签解析是在processAliasRegistration(Element ele)方法中完成的
protected void processAliasRegistration(Element ele) {
// 获取alisa标签name属性
String name = ele.getAttribute(NAME_ATTRIBUTE);
// 获取alisa标签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 {
// 进行别名注册
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标签解析中的别名注册一直,此处不再赘述
import标签解析
protected void importBeanDefinitionResource(Element ele) {
// 获取import标签的resource属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
// 如果不存在则不做任何处理
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// 解析占位符属性 格式如"${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// 判断资源是绝对路径还是相对路径
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*:"
}
// 如果是绝对路径则直接根据地址加载对应的配置文件
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 relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
} else {
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标签的处理,大致步骤如下
1.获取resource属性所表示的路径
2.解析路径中的属性占位符 如"${user.dir}"
3.判定location是绝对路径还是相对路径
4.如果是绝对路径则递归调用bean的解析过程,进行另一次解析
5.如果是相对路径则计算出绝对路径并进行解析
6.通知监听器,解析完成
beans标签解析
嵌入式beans标签与单独配置文件并没有太大差别,其原理是递归调用了beans的解析过程
转载请注明作者及出处,原文链接为:作者黄太洪 标题03.Spring IOC源码深度解析之默认标签的解析