开篇
上一篇解说了 Spring 中的标签蕴含自定义标签和默认标签,这两种形式存在较大不同,所以本文次要解说默认标签的解析过程。
默认标签的解析是在 parseDefaultElement 办法中。
该办法别离对不同标签做不同解决。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对import标签解决
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//对alias标签解决
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//对bean标签解决
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//对beans标签解决
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
doRegisterBeanDefinitions(ele);
}
}
Bean 标签的解析及注册
这四种中,咱们次要关注对 bean 标签的解析。bean 标签的解析是最简单且重要的。咱们进入 processBeanDefinition 办法。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
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);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
该段代码咱们还是先看时序图。
该办法 processBeanDefinition 大抵逻辑如下:
- 首先调用了
delegate.parseBeanDefinitionElement(ele)
办法进行元素解析。并返回 BeanDefinitionHolder 类型的 bdHolder,通过这个办法后,bdHolder 实例中曾经蕴含了配置文件中的各种属性,比方 class,name,id,alias 等 - 当返回的 bdHolder 不为空的状况下,若存在默认标签的子节点下还有自定义属性,还要对自定义标签进行解析。
- 解析实现后,须要对解析后的 bdHolder 进行注册,注册操作委托给了
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
办法 - 最初收回响应事件,告诉相干监听器,该 bean 曾经加载实现
解析 BeanDefinition
接下来咱们一点点剖析,首先咱们剖析该办法delegate.parseBeanDefinitionElement(ele)
。
该办法在BeanDefinitionParserDelegate类中。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//解析id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
//解析name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//宰割name属性
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 代码(1)
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
//如果不存在beanName那么依据Spring中提供的命名规定为以后bean生成对应的beanName
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("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;
}
该办法就是对默认标签解析的全过程,咱们当初能够能够看到对属性 id、name 的解析。
在以后办法次要实现的内容如下:
- 提取元素 id、name 属性
- 解析其余属性并封装到 GenericBeanDefinition 类型实例中
- 如果检测到 bean 没有指定 beanName,则应用默认规定生成一个 beanName
- 将获取到的信息封装到 BeanDefinitionHolder 实例中
咱们看一下代码中标注的代码(1)调用的parseBeanDefinitionElement
办法是如何对其余标签进行解析的。
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//解析class属性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
//解析parent属性
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//代码(1)创立用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//代码(2)解析默认bean的各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//提取 description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//代码(3)解析元数据
parseMetaElements(ele, bd);
//解析lookup-medthod属性 (用的很少,这里就不深刻介绍)
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-medthod属性(用的很少,这里就不深刻介绍)
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//代码(4)解析结构函数参数
parseConstructorArgElements(ele, bd);
//代码(5)解析property子元素
parsePropertyElements(ele, bd);
//解析qualifier子元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
创立用于属性承载的 BeanDefinition
咱们先看一下代码(1)调用的办法之前,咱们先再理解一下 BeanDefinition。
BeanDefinition 是一个接口,在 Spring 中存在三种实现:RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition。它们均继承自AbstractBeanDefinition,其中 BeanDefinition 是配置文件<bean>
元素在容器外部的表现形式。该标签领有 class、scope、lazy-init 等配置属性,BeanDefinition 也提供了对应的属性:beanClass、scope、lazyInit。
其中 RootBeanDefinition 是最罕用的实现类,个别对应<bean>
元素标签,而 GenericBeanDefinition 是 2.5 版本后退出的 bean 文件配置属性定义类,提供一站式服务类。
在配置文件中咱们能够父
<bean>
和子<bean>
,父就用 RootBeanDefinition 示意,而子就应用 ChildBeanDefinition 示意。一般的<bean>
就应用 RootBeanDefinition 来示意,AbstractBeanDefinition 则对两者独特类的信息进行形象。
Spring 通过 BeanDefinition 将配置文件的<bean>
转换为容器外部示意,并且将这些 BeanDefinition 注册到 BeanDefinitionRegistry 中。
Spring 容器的 BeanDefinitionRegistry 次要以 map 模式存储,后续操作能够间接从该类中获取配置信息。
但首先,咱们解析属性之前就须要创立用于承载属性的实例,也就是创立了咱们之前说的 GenericBeanDefinition 类型的实例。也就是代码(1)调用的createBeanDefinition(className, parent)
办法。
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进行加载类对象,否则只是记录className
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}else {
bd.setBeanClassName(className);
}
}
return bd;
}
至此,咱们就创立好了 GenericBeanDefinition 实例。
解析各种属性
当创立完用来承载 Bean 信息的 GenericBeanDefinition 实例后,就能够对 bean 信息的各种属性进行解析了。
首先咱们进入代码(2)parseBeanDefinitionAttributes
办法,该办法对 element 所有元素属性进行解析。
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable 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) {
//在嵌入BeanDefinition状况下,并且没有独自指定scope属性,则应用父类默认的属性
bd.setScope(containingBean.getScope());
}
//解析abstract属性
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
//解析lazy-init属性
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
//解析autowire属性
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
// 解析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 (isDefaultValue(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);
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;
}
该办法次要做的就是拿到各种属性对应的属性值放入 AbstractBeanDefinition 对应属性中。
解析子元素 meta
首先咱们回顾一下如何应用 meta 属性。
<bean id="myTestBean" class="cn.jack.MyTestBean">
<meta key="jack" value="HelloWorld"/>
</bean>
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
这段代码并没有体现在 MyTestBean 中,只是一个申明,在应用的时候能够应用BeanDefinition类的getAttribute(key)
办法获取。
接下来咱们看一下是如何解析的,进入代码(3)。
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
//获取以后节点所有元素
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//判断节点是否为meta
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
//结构BeanMetadataAttribute实例
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
//记录信息
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
解析子元素 constructor-arg
对构造函数的解析还是十分常见的,同时也是很简单,举个例子:
<bean id="myTestBean" class="cn.jack.MyTestBean">
<constructor-arg index="0">
<value>Jack</value>
</constructor-arg>
<constructor-arg index="1">
<value>hello</value>
</constructor-arg>
</bean>
该代码就是 Spring 中最根底的配置,主动寻找对应的结构器并在初始化的时候将设置的参数传入进去,接下来看一下如何解析。
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
//拿到bean所有子节点
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);
}
}
}
进入parseConstructorArgElement
办法。
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));
//代码(1)解析ele对应的属性元素
Object value = parsePropertyValue(ele, bd, null);
//应用ConstructorArgumentValues.ValueHolder类型封装解析进去的元素
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
//将name属性和type都封装到valueHolder中
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 {
//增加到BeanDefinition的ConstructorArgumentValues中,存入构造为Map
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());
//解析ele节点对应的属性值
Object value = parsePropertyValue(ele, bd, null);
//应用ConstructorArgumentValues.ValueHolder类型封装解析进去的元素
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
//将name属性和type都封装到valueHolder中
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
//增加到BeanDefinition的ConstructorArgumentValues中,因为没有index则存入构造为List
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
该办法并不是特地简单,首先提取 constructor-arg 上必要的属性(index、type、name)。
配置中指定了 index 的话操作步骤如下:
- 解析 constructor-arg 的子元素
- 应用 ConstructorArgumentValues.ValueHolder 类型封装解析后的元素
- 最初将 index、name、type 封装到 ValueHolder 类型中,并增加到 BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValues 属性中。
配置中没有指定 index 的话操作步骤如下:
- 解析 constructor-arg 的子元素
- 应用 ConstructorArgumentValues.ValueHolder 类型封装解析后的元素
- 最初将 index、name、type 封装到 ValueHolder 类型中,并增加到 BeanDefinition 的 constructorArgumentValues 的 genericArgumentValues 属性中。
理解完流程之后,咱们看一下具体是如何进行解析的,进入代码(1)parsePropertyValue
的办法中。
public Object parsePropertyValue(Element ele, BeanDefinition bd, @Nullable String propertyName) {
String elementName = (propertyName != null ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element");
// 获取ele节点的子节点,一个属性只能对应一种类型:ref/value/list等
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
//跳过meta节点或description节点
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
//只能有一个子节点,否则异样
if (subElement != null) {
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中不存在: 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属性解决,应用RuntimeBeanReference封装对应的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封装
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,也没有子元素则抛出异样
// Neither child element nor "ref" or "value" attribute found.
error(elementName + " must specify a ref or value", ele);
return null;
}
}
该办法对构造函数中属性的元素解析,通过以下过程:
- 跳过 description 或者 meta
- 提取 constructor-arg 上的 ref 和 value 属性,随后进行校验
-
ref 属性解决,应用 RuntimeBeanReference 封装对应的 ref 名称,比方:
<constructor-arg ref="a"></constructor-arg>
-
value 属性的解决,应用 TypedStringValue 封装,比方:
<constructor-arg value="a"></constructor-arg>
-
子元素解决,比方:
<bean id="myTestBean" class="cn.jack.MyTestBean"> <constructor-arg> <map> <entry key="jack" value="nihao"></entry> </map> </constructor-arg> </bean>
对于子元素的解决,比方这里提到的退出了 map 元素,是如何解决的?具体在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);
}
//解析是否为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 a parent context.
//解析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;
}
//解析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;
}
}
在该办法中实现了所有反对的类型的分类解决,到此就曾经理分明构造函数是如何解析了,这里就不深入研究如何解析 list、map 等元素了。
解析子元素 property
在剖析完构造函数后,咱们能够接着往下看,这里防止遗记咱们再看一下目前到哪里了。
到这里咱们先回顾一下如何应用 property 属性。当然,property 属性里也能够应用 list 等类型的元素。
<bean id="myTestBean" class="cn.jack.MyTestBean">
<property name="testStr" value="jack"/>
</bean>
public class MyTestBean {
private String testStr = "testStr";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
}
接下来咱们看一下是如何解析的。
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
//获取到beanElement的所有子节点
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)) {
//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));
//解析实现后增加到BeanDefinition的propertyValues属性中
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
和之前解说的过程都差不多,都是先获取所有子标签而后进行遍历进行解析,获取对应的 name、value 值进行封装。
解析子元素 qualifier
该元素咱们个别应用注解偏多,次要就是当接口存在多个实现类时候,在咱们注入时指定某一个实现类,这样 Spring 容器就能够找到对应的 bean。因为在 Spring 中候选的 Bean 数目必须有且仅有一个。解析过程和之前都差不多,这里就不再赘述。
<bean id="myTestBean" class="cn.jack.MyTestBean">
<qualifier type="org.springframework.beans.factory.annotation.Qualifier" value="Bean的名称"/>
</bean>
AbstractBeanDefinition 属性
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
至此,咱们就实现了对 XML 文档到 GenericBeanDefinition 的转换,XML 中的配置都能够在 GenericBeanDefinition 中看到,但 GenericBeanDefinition 只是子类,大部分属性都在 AbstractBeanDefinition 中。咱们回顾一下都有哪些配置。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 此处省略动态变量以及final变量
@Nullable
private volatile Object beanClass;
/**
* bean的作用范畴,对应bean属性scope
*/
@Nullable
private String scope = SCOPE_DEFAULT;
/**
* 是否是形象,对应bean属性abstract
*/
private boolean abstractFlag = false;
/**
* 是否提早加载,对应bean属性lazy-init
*/
private boolean lazyInit = false;
/**
* 主动注入模式,对应bean属性autowire
*/
private int autowireMode = AUTOWIRE_NO;
/**
* 依赖查看,Spring 3.0后弃用这个属性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
/**
* 用来示意一个bean的实例化依附另一个bean先实例化,对应bean属性depend-on
*/
@Nullable
private String[] dependsOn;
/**
* autowire-candidate属性设置为false,这样容器在查找主动拆卸对象时,
* 将不思考该bean,即它不会被思考作为其余bean主动拆卸的候选者,
* 然而该bean自身还是能够应用主动拆卸来注入其余bean的
*/
private boolean autowireCandidate = true;
/**
* 主动拆卸时呈现多个bean候选者时,将作为首选者,对应bean属性primary
*/
private boolean primary = false;
/**
* 用于记录Qualifier,对应子元素qualifier
*/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
@Nullable
private Supplier<?> instanceSupplier;
/**
* 容许拜访非公开的结构器和办法,程序设置
*/
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为true,
* 如果为false,则在以下状况
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 抛出异样,因为Spring无奈精确定位哪个构造函数程序设置
*/
private boolean lenientConstructorResolution = true;
/**
* 对应bean属性factory-bean,用法:
* <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
* <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
*/
@Nullable
private String factoryBeanName;
/**
* 对应bean属性factory-method
*/
@Nullable
private String factoryMethodName;
/**
* 记录构造函数注入属性,对应bean属性constructor-arg
*/
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
/**
* 一般属性汇合
*/
@Nullable
private MutablePropertyValues propertyValues;
/**
* 办法重写的持有者,记录lookup-method、replaced-method元素
*/
@Nullable
private MethodOverrides methodOverrides;
/**
* 初始化办法,对应bean属性init-method
*/
@Nullable
private String initMethodName;
/**
* 销毁办法,对应bean属性destroy-method
*/
@Nullable
private String destroyMethodName;
/**
* 是否执行init-method,程序设置
*/
private boolean enforceInitMethod = true;
/**
* 是否执行destroy-method,程序设置
*/
private boolean enforceDestroyMethod = true;
/**
* 是否是用户定义的而不是应用程序自身定义的,创立AOP时候为true,程序设置
*/
private boolean synthetic = false;
/**
* 定义这个bean的利用,APPLICATION:用户,INFRASTRUCTURE:齐全外部应用,与用户无关,
* SUPPORT:某些简单配置的一部分
* 程序设置
*/
private int role = BeanDefinition.ROLE_APPLICATION;
/**
* bean的形容信息
*/
@Nullable
private String description;
/**
* 这个bean定义的资源
*/
@Nullable
private Resource resource;
}
解析默认标签中的自定义标签元素
到目前为止,咱们曾经剖析了BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
这行代码,接下来咱们持续剖析bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
这行代码。
咱们先理解一下这行代码的大略作用,从语义上来剖析:如果需要的话就对 BeanDefinition 进行装璜,相似于如下场景:
<bean id="myTestBean" class="cn.jack.MyTestBean">
<mybean:user username="jack"/>
</bean>
当 Spring 中的 bean 应用的是默认标签配置,然而子元素却应用自定义配置的时候,这行代码就会执行。
然而为什么会在默认类型解析中独自增加一个自定义类型呢?首先这个自定义类型并不是以 bean 的模式呈现的,在这里的自定义类型其实相当于是属性。
咱们持续剖析该办法代码。
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
在调用decorateBeanDefinitionIfRequired
办法时,第三个参数传入为 null,该参数是父类 bean,当对某个嵌套配置剖析时须要传递父类的 BeanDefinition,其实就是为了应用父类的 scope 属性,如果子类没有设置 scope 属性则应用父类的 scope 属性。这里是顶层配置,所以传递为 null。
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// 遍历节点,查看是否存在实用于装璜的属性
// 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;
}
最终都调用到了decorateIfRequired
办法,咱们进入此办法查看。
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/schema/")) {
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 进行下一步解析,该局部会在自定义标签解析中解说。
总结:该办法的作用就是对自定义标签或者自定义属性进行解决,而后找到对应的命名空间处理器进行进一步的解析。
注册解析的 BeanDefinition
到这里,咱们对配置文件的解析、装璜都曾经实现,当初的 BeanDefinition 曾经满足应用要求了,后续就剩下了注册工作。
也就是 processBeanDefinition 办法中的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 alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
该办法获取到 beanName 后,最终 BeanDefinition 都会注册到BeanDefinitionRegistry中,该办法分为两局部,一种为 beanName 注册形式和别名注册形式。
对于 BeanDefinition 的注册,不仅仅是将 BeanDefinition 放入 map 中,而后 beanName 作为 key。除此之外还做了别的事件。
进入 DefaultListableBeanFactory 类实现中。
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 {
//注册前最初一次校验,针对AbstractBeanDefinition中的methodOverrides校验
//校验methodOverrides是否与工厂办法并存,或者methodOverrides对应的办法压根不存在
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//判断是否曾经存在bean
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果对应的beanName曾经注册过并且不容许笼罩,则抛出异样
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//存入BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//是否曾经开始创立bean
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 因为beanDefinitionMap是全局变量,这里会存在并发拜访的状况
synchronized (this.beanDefinitionMap) {
//存入BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
//存入BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
//记录beanName
this.beanDefinitionNames.add(beanName);
//从factoryBeanCreatedCache中移除掉这个beanName
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置所有beanName对应的缓存
resetBeanDefinition(beanName);
}
}
注册 bean 分为以下四步:
- 对 AbstractBeanDefinition 的 methodOverrides 属性校验
- 如果曾经注册过并且不容许笼罩则抛出异样,否则间接笼罩
- 退出 map 缓存
- 革除解析前的 beanName 缓存
之后咱们再看通过别名注册就简略多了。
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
//如果beanName与alias雷同则不记录alias,并删除对应的alias
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
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 define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
//确保增加的没有name和alias值相同的数据且alias和name不相等
checkForAliasCircle(name, alias);
//存入map中
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
从该办法可知,注册 alias 步骤如下:
- alias 和 beanName 雷同状况解决,如果雷同则不须要解决并删除原有 alias
- 笼罩校验解决
- alias 循环查看
- 注册 alias
告诉监听器解析及注册实现
在注册实现后,当开发人员须要对注册 BeanDefinition 事件进行监听时能够通过注册监听器形式将解决逻辑写入监听器中,在 Spring 中并没有对此事件做任何逻辑解决。
总结
到这里,Bean 的解析和注册过程曾经全副 OK 了。
回顾一下,解析 BeanDefinition 的入口在 DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()
。该办法会依据命令空间来判断标签是默认标签还是自定义标签,其中默认标签由 parseDefaultElement()
实现,自定义标签由 parseCustomElement()
实现。在默认标签解析中,会依据标签名称的不同进行 import 、alias 、bean 、beans 四大标签进行解决,其中 bean 标签的解析为外围,它由 processBeanDefinition()
办法实现。processBeanDefinition()
开始进入解析外围工作,分为三步:
- 解析默认标签:
BeanDefinitionParserDelegate.parseBeanDefinitionElement()
- 解析默认标签下的自定义标签:
BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()
- 注册解析的 BeanDefinition:
BeanDefinitionReaderUtils.registerBeanDefinition()
在默认标签解析过程中,外围工作由 parseBeanDefinitionElement()
办法实现,该办法会顺次解析 Bean 标签的属性、各个子元素,解析实现后返回一个 GenericBeanDefinition 实例对象。
最初通过registerBeanDefinition办法进行对BeanDefinition进行注册后就功败垂成了。
发表回复