参考资料:
《Spring IoC源码学习:parseDefaultElement 详解》
前文:
《Spring IOC:obtainFreshBeanFactory调用链》
写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。
目录
二、parseBeanDefinitionElement调用链
4、parseBeanDefinitionAttributes
三、parseConstructorArgElements调用链
一、parseDefaultElement调用链
1、parseDefaultElement
在前文中,parseBeanDefinitions方法对于xml配置的bean采用parseDefaultElement方法逐个解析。
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
// public static final String BEAN_ELEMENT = "bean";
public static final String NESTED_BEANS_ELEMENT = "beans";
public static final String ALIAS_ELEMENT = "alias";
public static final String NAME_ATTRIBUTE = "name";
public static final String ALIAS_ATTRIBUTE = "alias";
public static final String IMPORT_ELEMENT = "import";
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 1.对import标签的处理
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 2.对alias标签的处理
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 3.对bean标签的处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 4.对beans标签的处理
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
2、processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 进行节点定义解析, 经过这个方法后,bdHolder会包含一个Bean节点的所有属性,例如name、class、id
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 若存在默认标签的子节点下再有自定义属性,需要再次对自定义标签再进行解析(基本不用,不做深入解析)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 解析节点定义完成后,需要对解析后的bdHolder进行注册
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));
}
}
二、parseBeanDefinitionElement调用链
1、parseBeanDefinitionElement
这一步在获取到<bean>节点后,解析id以及beanName属性,并调用parseBeanDefinitionElement方法封装成beanDefinition
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 解析name和id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 分割name属性(通过逗号或分号)
// public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
// 例如:<bean name="demoService,demoServiceAlias" class=""/>,分割后aliases为[demoService, demoServiceAlias]
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// beanName默认使用id
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
// 如果id为空,并且aliases不为空,则取aliases的第一个元素作为beanName,其他的仍作为别名
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是否在同一个 <beans> 下已经存在
checkNameUniqueness(beanName, aliases, ele);
}
// 进一步解析bean的其他所有属性并统一封装至GenericBeanDefinition类型实例中
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
// 如果bean定义存在,但是beanName为空,则用Spring默认的生成规则为当前bean生成beanName
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// Spring提供的生成规则生成beanName
// 例如:com.joonwhee.open.demo.service.impl.DemoServiceImpl#0
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
// 如果Spring默认的生成规则生成的beanName为:类名加后缀,则将类名注册为别名
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);
// 将bean定义、beanName、bean别名数组封装成BeanDefinitionHolder
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
2、 parseBeanDefinitionElement
上一步获取了当前<bean>的id以及beanName,这里进一步解析该节点的其他属性,首先是class、parent节点。然后我们根据这两个属性创建beanDefinition对象bd,继而解析其余各节点(如constructor-arg、property)并置入bd中
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);
}
// 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析bean的各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 提取description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析constructor-arg子节点
parseConstructorArgElements(ele, bd);
// 解析property子节点
parsePropertyElements(ele, bd);
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;
}
3、createBeanDefinition
根据className、parentName、beanDefinition、BeanClassLoader利用反射创建对象bd
// BeanDefinitionParserDelegate.java
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
// BeanDefinitionReaderUtils.java
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
4、parseBeanDefinitionAttributes
解析本节点中各个属性,并置入bd(AbstractBeanDefinition 对象)中,包括scope、depends-on等(但不包含constructor-arg、property)
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析singleton属性
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
// singleton属性已经不支持, 如果使用了会直接抛出异常, 请使用scope属性代替
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
// 解析scope属性
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());
}
// 解析abstract属性
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 解析lazy-init属性, 默认为false
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// 解析autowire属性
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// 解析dependency-check属性
String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
// 解析depends-on属性
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// 解析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));
}
// 解析primary属性
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
// 解析init-method属性
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);
}
}
// 解析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);
}
}
// 解析factory-method属性
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
// 解析factory-bean属性
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
三、parseConstructorArgElements调用链
从这一步开始,针对构造方法初始化的bean进行解析
1、parseConstructorArgElements
拿到 beanEle的所有子节点,遍历解析所有是constructor-arg节点的子节点。(bean 中必须要有相应的构造函数才可以使用,否则会报错)
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
// 拿到beanEle节点的所有子节点
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);
}
}
}
2、parseConstructorArgElement
constructor-arg中index用来指定对应构造方法中的第几个参数。在index存在的情况下,先判断index是否重复指定,如果是则抛出异常;如果不重复,则将 index 和 valueHolder 以 key-value 形式添加至当前BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中(用于前面判断index是否重复指定)
无论是否存在index,我们都会先调用parsePropertyValue方法对该constructor-arg节点进行进一步的解析。
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
// 获取基础属性index、type、name等属性
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 {
// index不为空的处理
this.parseState.push(new ConstructorArgumentEntry(index));
// 解析ele节点对应的属性值
Object value = parsePropertyValue(ele, bd, null);
// 使用ConstructorArgumentValues.ValueHolder类型来封装解析出来的元素
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
// 将type属性封装到ConstructorArgumentValues.ValueHolder
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
// 将name属性封装到ConstructorArgumentValues.ValueHolder
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
// 判断index是否重复指定, 如果是则抛出异常
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
}
else {
// 将index和valueHolder以key-value形式添加至当前BeanDefinition的constructorArgumentValues
// 的indexedArgumentValues属性中,(用于上面判断index是否重复指定)
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类型来封装解析出来的元素
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
// 将type属性封装到ConstructorArgumentValues.ValueHolder
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
// 将name属性封装到ConstructorArgumentValues.ValueHolder
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
// 将valueHolder添加至当前BeanDefinition的constructorArgumentValues的genericArgumentValues属性中
// 与上面的indexedArgumentValues类似,上面有index存为map,这边没index存为list
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
3、parsePropertyValue
constructor-arg节点赋值可以直接使用value,或这ref调用其他已创建对象,还可以使用子节点(只可以有1个,子节点可用于实例化list、map等对象),对应着三种不同的赋值方式,分别有三套逻辑进行解析。子节点解析方法parsePropertySubElement同样包含针对ref、value的处理方法。
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
// Should only have one child element: ref, value, list, etc.
// 拿到ele节点的子节点,例如list、map
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) {
// 只能有1个子节点,否则抛出异常
error(elementName + " must not contain more than one sub-element", ele);
} else {
// 找到子节点,赋值给subElement
subElement = (Element) node;
}
}
}
// 解析constructor-arg上的ref属性
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
// 解析constructor-arg上的value属性
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
// 合法性校验。在constructor-arg上:ref属性、value属性、子节点,三者只能有1个,因为这三个都是用来表示该节点的值。
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属性的处理,使用RuntimeBeanReference封装对应的ref值(该ref值指向另一个bean的beanName),
// RuntimeBeanReference起到占位符的作用,ref指向的beanName将在运行时被解析成真正的bean实例引用
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封装
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属性,也没有子节点,没法获取ele节点的值,直接抛异常
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
4、parsePropertySubElement
调用parsePropertySubElement方法对子节点中各节点进行解析,其中parseValueElement方法解析value节点最常用。
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);
}
// 解析bean节点
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
// 解析ref节点
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)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in a parent context.
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)) {
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
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;
}
}
5、parseValueElement
解析value节点(最常用)
public Object parseValueElement(Element ele, String defaultTypeName) {
// It's a literal value.
// 拿到ele节点值
String value = DomUtils.getTextValue(ele);
// 拿到ele节点的type属性
String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);
String typeName = specifiedTypeName;
if (!StringUtils.hasText(typeName)) {
// ele节点没有type属性则则使用入参defaultTypeName
typeName = defaultTypeName;
}
try {
// 使用value和type构建TypedStringValue
TypedStringValue typedValue = buildTypedStringValue(value, typeName);
typedValue.setSource(extractSource(ele));
typedValue.setSpecifiedTypeName(specifiedTypeName);
return typedValue;
}
catch (ClassNotFoundException ex) {
error("Type class [" + typeName + "] not found for <value> element", ele, ex);
return value;
}
}
6、buildTypedStringValue
使用 value 和 typeName 构建 TypedStringValue
protected TypedStringValue buildTypedStringValue(String value, String targetTypeName)
throws ClassNotFoundException {
ClassLoader classLoader = this.readerContext.getBeanClassLoader();
TypedStringValue typedValue;
// targetTypeName为空,则只使用value来构建TypedStringValue
if (!StringUtils.hasText(targetTypeName)) {
typedValue = new TypedStringValue(value);
}
// targetTypeName不为空,并且classLoader不为null
else if (classLoader != null) {
// 利用反射,构建出type的Class,如果type是基本类型,或者 java.lang 包下的常用类,
// 可以直接从缓存(primitiveTypeNameMap、commonClassCache)中获取
Class<?> targetType = ClassUtils.forName(targetTypeName, classLoader);
typedValue = new TypedStringValue(value, targetType);
} else {
typedValue = new TypedStringValue(value, targetTypeName);
}
return typedValue;
}
四、parsePropertyElements调用链
1、parsePropertyElements
和上文中解析constructor-arg节点一样,遍历解析beanEle节点的所有子节点找出直接使用property赋值的节点。(property节点调用set方法赋值,因此bean中的属性必须要有set方法才可以使用,否则会报错)
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// 拿到beanEle节点的所有子节点
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);
}
}
}
2、parsePropertyElement
依旧和构造方法注册一致,调用parsePropertyValue方法解析节点。不过这里不用再判断index节点了。
public void parsePropertyElement(Element ele, BeanDefinition bd) {
// 拿到name属性
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
// name属性为必要属性,如果没有配置,则抛出异常
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 校验在相同bean节点下,是否存在相同的name属性,如果存在则抛出异常
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 解析属性值
Object val = parsePropertyValue(ele, bd, propertyName);
// 将解析的属性值和属性name封装成PropertyValue
PropertyValue pv = new PropertyValue(propertyName, val);
// 解析meta节点(基本不用,不深入解析)
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
// 将解析出来的PropertyValue,添加到BeanDefinition的propertyValues属性中(上面的重复校验用到)
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
五、registerBeanDefinition调用链
在前文中,我们已经得到了beanDefinition、beanName、aliasesArray这三个对象,继而创建了BeanDefinitionHolder对象,然后就可以开始注册操作了。
1、registerBeanDefinition
首先调用registerBeanDefinition方法将beanName、BeanDefinition 到缓存中。然后如果有别名,则调用registerAlias方法注册 bean 的 beanName 和对应的别名映射到 aliasMap 缓存中。
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 拿到beanName
String beanName = definitionHolder.getBeanName();
// 注册beanName、BeanDefinition到缓存中(核心逻辑),实现类为; DefaultListableBeanFactory
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 注册bean名称的别名(如果有的话)
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// 3.注册bean的beanName和对应的别名映射到缓存中(缓存:aliasMap)
registry.registerAlias(beanName, alias);
}
}
}
2、registerBeanDefinition
将 beanName 添加到 beanDefinitionNames 缓存,将 beanName 和 BeanDefinition 的映射关系添加到beanDefinitionMap 缓存。
如果 beanName不重复,对于我们当前正在解析的 obtainFreshBeanFactory 方法来说,因为 bean 创建还未开始,因此进行缓存的注册。
如果 beanName 重复,并且该 beanName 已经存在单例对象,则会调用 resetBeanDefinition 方法。
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// beanName和beanDefinition为空校验
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 注册前的最后校验
((AbstractBeanDefinition) beanDefinition).validate();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
// 首先根据beanName从beanDefinitionMap缓存中尝试获取
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
// beanName存在于缓存中
if (!isAllowBeanDefinitionOverriding()) {
// 如果不允许相同beanName重新注册,则直接抛出异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
// logs,此处代码省略
}
// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存(以供后续创建bean时使用)
this.beanDefinitionMap.put(beanName, beanDefinition);
} else {
// beanName不存在于缓存中
if (hasBeanCreationStarted()) {
// bean创建阶段已经开始
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
this.beanDefinitionMap.put(beanName, beanDefinition);
// 将本次传进来的beanName 加入beanDefinitionNames缓存
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
// 将beanName从manualSingletonNames缓存移除
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
} else {
// bean创建阶段还未开始
// Still in startup registration phase
// 将本次传进来的beanName 和 BeanDefinition映射放入beanDefinitionMap缓存
this.beanDefinitionMap.put(beanName, beanDefinition);
// 将本次传进来的beanName 加入beanDefinitionNames缓存
this.beanDefinitionNames.add(beanName);
// 将beanName从manualSingletonNames缓存移除
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// 如果存在相同beanName的BeanDefinition,并且beanName已经存在单例对象,则将该beanName对应的缓存信息、单例对象清除,
// 因为这些对象都是通过oldBeanDefinition创建出来的,需要被覆盖掉的,
// 我们需要用新的BeanDefinition(也就是本次传进来的beanDefinition)来创建这些缓存和单例对象
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
补充:
1、hasBeanCreationStarted()这是做什么的?为什么这种情况下需要加锁?
这里主要是判断是不是已经有bean被创建,正常来说到目前为止,我们并有创建任何的bean,到现在我们做的仅仅是解析配置,并注册beanDefinition,如果有bean被创建意味着着我们已经开始利用容器去进行我们的业务操作了。此时,Spring容器无法保证使用者是在线程安全的情况下调用了(即我们的业务操作可能会去直接新建bean的操作),也就是无法保证下面的代码不会出现线程安全问题,所以需要加锁。
2、为什么要将this.beanDefinitionMap.put(beanName, beanDefinition)也放入同步代码块中?
我们之前已经知道了beanDefinitionNames是要按照注册顺序保存的,所以必须要将put操作也进行同步,不然可能出现顺序错误。
3、为什么在加锁后给集合中添加元素还要进行一次类似于复制的操作(addAll)?
我们在业务操作过程中,很可能调用Spring的某些方法,这些方法需要遍历beanDefinitionNames,这些遍历方法通常都是使用迭代器的,我们知道迭代过程中如果我们又对集合进行了添加,移除的操作,会引发快速失败机制如果对快速失败机制不熟悉的请自行百度。为了避免这种情况所以选择新建一个集合然后进行复制。
3、resetBeanDefinition
将该beanName的mergedBeanDefinitions 缓存信息删除,将单例缓存删除的该beanName删除。如果存在子 bean 定义,则递归重置。
protected void resetBeanDefinition(String beanName) {
// 删除beanName的mergedBeanDefinitions缓存(如果有的话)
clearMergedBeanDefinition(beanName);
// 从单例缓存中删除该beanName对应的bean(如果有的话)
destroySingleton(beanName);
// 重置beanName的所有子Bean定义(递归)
for (String bdName : this.beanDefinitionNames) {
if (!beanName.equals(bdName)) {
BeanDefinition bd = this.beanDefinitionMap.get(bdName);
// 当前遍历的BeanDefinition的parentName为beanName,则递归调用resetBeanDefinition进行重置
if (beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
4、registerAlias
比较简单,将别名和 beanName 注册到 aliasMap 缓存。
@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相同,则不算别名,从aliasMap缓存中移除
if (alias.equals(name)) {
this.aliasMap.remove(alias);
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
// 如果别名已经注册过,直接返回
return;
}
// 如果存在相同的别名,并且不允许别名覆盖,则抛出异常
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
}
// 检查name和alias是否存在循环引用。例如A的别名为B,B的别名为A
checkForAliasCircle(name, alias);
// 将别名和beanName的映射放到aliasMap缓存中
this.aliasMap.put(alias, name);
}
}
总结:
1、对于传入parseDefaultElement方法的节点调用parseBeanDefinitionElement方法创建AbstractBeanDefinition对象beanDefinition,并将该节点的各类信息解析、存入beanDefinition对象中。
2、将beanDefinition、beanName、aliasesArray构建成 BeanDefinitionHolder对象并返回,为后续注册做准备。
3、将 BeanDefinition 和 beanName注册到BeanFactory的缓存中,即beanDefinitionNames (存储beanName集合,类型为ArrayList),以及beanDefinitionMap(beanName和BeanDefinition映射,类型为ConcurrentHashMap)。