前言
内容主要参考自《Spring源码深度解析》一书,算是读书笔记或是原书的补充。进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情。
本文主要涉及书中第三章的部分,依照书中内容以及个人理解对Spring进行了注释,详见Github仓库:https://github.com/MrSorrow/spring-framework
在上一篇文章中,我们已经对Spring读取配置文件注册Bean的流程大致了解了,着重跟随代码的流程一步步查看Spring是如何为DI进行准备的。当然我们最终没有看到它是如何一步步解析XML中的标签并生成我们的依赖对象并进行注入的,那么本文接着来继续学习Spring是如何解析内置标签的。
I. bean标签的解析及注册
默认标签解析是在 parseDefaultElement
中实现的,函数的功能主要是对四种标签(import,alias,bean 和 beans)进行不同的解析。
/**
* 解析默认标签<import> <alias> <bean> 嵌套的<beans>
* @param ele 每一个标签
* @param delegate 翻译为:bean定义解析的代表
*/
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)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
四种标签中,其中 bean 标签最为复杂常见,下面先介绍 bean 标签的解析过程。点进 processBeanDefinition
函数:
/**
* 解析<bean>标签
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 委托BeanDefinitionParserDelegate对ele进行解析,bdHolder已经包含配置文件中配置的各种属性,例如class,name,id,alias
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 默认标签下若存在自定义属性,还需要再次对自定义标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance. 解析完成,需要对解析后的btHolder进行注册
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));
}
}
传入的 Element ele
相当于一个 <bean>···</bean>
包含的内容。该函数的时序逻辑如下图所示:
该函数主要完成四件事:
- 委托
BeanDefinitionParserDelegate
对 ele 进行解析,返回的BeanDefinitionHolder
类型的bdHolder
已经包含配置文件中对该 bean 配置的各种属性,例如 class, name, id, alias; - 如果返回的
bdHolder
不为空,默认 bean 标签下若存在自定义属性,还需要再次对自定义标签进行解析; - 解析完成,需要对解析后的btHolder进行注册。同样,注册操作交给了
BeanDefinitionReaderUtils
的registerBeanDefinition
方法去完成; - 最后发出注册响应事件,通知相关的监听器,这个bean已经加载完成。
解析BeanDefinition
下面就针对上面的四步骤进行一一详细跟踪。从元素解析及信息提取开始,我们点进 BeanDefinitionParserDelegate
的 parseBeanDefinitionElement
方法:
/**
* bean标签信息提取
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
/**
* bean标签信息提取
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 1. 获取id和name属性值
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// name可能设置了多个,要解析成数组添加至aliases
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
// 以','、';'或' '分割
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 默认设置了id属性,则bean的名称就为id
// 如果id不存在name属性存在,则bean的名称设置为alias的第一个元素,剩下的作为别名
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
// 检验bean是否已经被用,没有重复则保存bean的名称与别名
checkNameUniqueness(beanName, aliases, ele);
}
// 2. 进一步解析其他所有属性
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 3. 如果id和name属性都没有指定,则Spring会自行创建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);
// 4. 将解析完成的信息封装至BeanDefinitionHolder实例中
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
通过阅读源码以及注释,可以看到,该函数也主要分成四个步骤:
- 在全面解析所有属性前,先提取元素中的 id 和 name 属性;
- 进一步解析其他所有属性,并封装信息至
GenericBeanDefinition
类型的实例对象beanDefinition
中; - 如果检测到 bean 没有指定的 beanName,那么Spring使用默认规则给该 bean 生成 beanName;
- 将解析出的所有信息封装到
BeanDefinitionHolder
实例对象中。
第 1 步逻辑简单,而关于 Spring 对 bean 的 name设置和我们平时熟知的规则是一致的。我们进一步查看步骤 2 解析其他属性的函数 parseBeanDefinitionElement(ele, beanName, containingBean)
:
/**
* bean标签除了id和name其他属性信息的解析
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
*/
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 解析class属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition对象,创建随后立刻保存class和parent属性
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 硬编码解析默认bean的各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 设置描述 内容来自description子元素
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析元数据<meta key="" value="">
parseMetaElements(ele, bd);
// 解析lookup-method属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replace-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析构造函数参数
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;
}
可以看到,有关 bean
的其他所有属性的解析都在该函数中完成了。开始我们可以看到直接解析 class
和 parent
属性。然后创建了用于承载属性的 AbstractBeanDefinition
类型的 GenericBeanDefinition
对象,创建随后立刻保存 class
和 parent
属性。
① 创建用于承载属性的BeanDefinition
BeanDefinition
本身是一个接口,Spring 中提供了三种相关的实现类,如下图所示。三种实现类均继承自该接口的抽象实现类 AbstractBeanDefinition
。BeanDefinition 是配置文件 <bean> 元素标签在容器中的内部表示形式。 <bean>元素标签拥有的class、scope、lazy-init 等配置属性对应 BeanDefinition 也有相应的 beanClass、scope、lazyInit 等属性进行一一对应。
其中,RootBeanDefinition
是最常用的实现类,它对应一般性的元素标签;GenericBeanDefinition
是自2.5版本以后新加入的 bean 文件配置属性定义类,是一站式服务类。在配置文件中用 parent 属性可以定义父 <bean> 和子 <bean> ,父 <bean> 用 RootBeanDefinition
表示,而子 <bean> 用 ChildBeanDefiniton
表示,而没有父 <bean> 的 <bean> 就使用 RootBeanDefinition
表示。AbstractBeanDefinition
是对两者共同的类信息进行抽象。
Spring 通过 BeanDefinition
将配置文件中的配置信息转换为容器的内部表示,并将这些 BeanDefinition
注册到 BeanDefinitionRegistry
中。Spring 容器的 BeanDefinitionRegistry
就像是 Spring 配置信息的内存数据库,主要是以 map 的形式保存,后续操作直接从 BeanDefinitionRegistry
中读取配置信息。
因此,要想解析保存 bean 的属性信息,需要先创建 BeanDefinition
的实例。代码中实际调用 createBeanDefinition
方法创建了 GenericBeanDefinition
类型的实例来保存属性信息。
/**基于class和parent创建一个bean definition
* Create a bean definition for the given class name and parent name.
* @param className the name of the bean class
* @param parentName the name of the bean's parent bean
* @return the newly created bean definition
* @throws ClassNotFoundException if bean class resolution was attempted but failed
*/
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
实际则又委托 BeanDefinitionReaderUtils
去进行创建:
/**
* Create a new GenericBeanDefinition for the given parent name and class name,
* eagerly loading the bean class if a ClassLoader has been specified.
* @param parentName the name of the parent bean, if any
* @param className the name of the bean class, if any
* @param classLoader the ClassLoader to use for loading bean classes
* (can be {@code null} to just register bean classes by name)
* @return the bean definition
* @throws ClassNotFoundException if the bean class could not be loaded
*/
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
// 创建GenericBeanDefinition实例
GenericBeanDefinition bd = new GenericBeanDefinition();
// 设置bd的parentName(bean标签的parent属性可能为空)
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
// 如果classLoader不为空,则使用以传入的classLoader同一虚拟机加载类对象,否则只是记录className
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
② 进一步解析各种属性
创建完 bean 信息的承载实例后,便可以进行各种 bean 配置属性的解析了。先进入硬编码解析默认bean的各种属性的方法 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd)
;
/**
* 硬编码解析默认bean的各种属性,返回保存了配置信息的bd
*/
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 判断是否含有singleton属性,新版本要用scope属性
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
} else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
// 设置abstract属性
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
// 设置lazy-init属性,默认default为true
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));
// 设置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);
bd.setInitMethodName(initMethodName);
}
else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 设置destory-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(