Spring 源码阅读-1-xml加载解析
XML加载解析
1、 加载 Bean 定义
1.1 解析XML 处理Document
XmlBeanDefinitionReader#loadBeanDefinitions
/**
* 加载xml资源,解析xml所有标签,将xml对应的bean封装为BeanDefinition(真实类型为GenericBeanDefinition),并注册
* 返回加载的BeanDefinition数量
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// EncodedResource 增加了encoding以及charset属性
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// 将当前加载的xml记录一下。正在加载
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
// 获取配置资源输入文件流对象(xml文件输入流)
InputStream inputStream = encodedResource.getResource().getInputStream();
// org.xml.sax.InputSource
// 封装为 InputSource 为 xml解析做准备
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正的处理
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
....
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
// 加载结束删除
this.resourcesCurrentlyBeingLoaded.remove();
}
}
此方法为加载xml的最上层方法,首先接在xml配置文件,然后将文件封装为InputSource,然后将真正对xml的处理交给doLoadBeanDefinitions方法处理。
XmlBeanDefinitionReader#doLoadBeanDefinitions
/**
* 将任务进一步拆分
* 将xml文件解析封装为Document
* 然后根据Document注册bean信息
* @param inputSource
* @param resource
* @return
* @throws BeanDefinitionStoreException
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 获取对 XML 文件的验证模式并加载xml文件为document
Document doc = doLoadDocument(inputSource, resource);
// 根据返回的 Document 注册 Bean 信息
return registerBeanDefinitions(doc, resource);
}
...
}
此方法进一步拆分任务,DefaultDocumentLoader#loadDocument 将xml流解析成Document对象,XmlBeanDefinitionReader#registerBeanDefinitions根据Document对象进一步解析,注册bean信息。
XmlBeanDefinitionReader#doLoadDocument
/**
* 解析XML
* 允许使用标准 XML 实体将 XML 片段包含到应用程序上下文定义中,例如将大型 XML 文件拆分为各种模块
*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
// getValidationModeForResource 获取对 XML 文件的验证模式 (1、dtd 2、xsd) 如果未设置将加载流自动判断模式
// getEntityResolver XML 解析器
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
XmlBeanDefinitionReader#registerBeanDefinitions中通过DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions在给定的根 元素中注册每个 bean 定义。
protected void doRegisterBeanDefinitions(Element root) {
....
if (this.delegate.isDefaultNamespace(root)) {
// 处理 beans 的 profile属性 可以配置多套环境
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 前置处理留给子类处理
preProcessXml(root);
// 真正的解析bean定义
parseBeanDefinitions(root, this.delegate);
// 后置处理留给子类处理
postProcessXml(root);
....
}
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 对beans 处理
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
// 对 bean处理
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 处理 默认的 http //w ww.springframework org/scherna beans
parseDefaultElement(ele, delegate);
}
else {
// 处理自定义的 比如 tx下的
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
到此,开始根据root(beans)节点循环解析子标签,子标签又分为默认标签以及自定义标签,这两种处理方式截然不同。一下都是在说默认标签,自定义标签单独说明。
到此已完成的任务:
- 加载xml resource资源,并且封装为EncodedResource(可以设置charset)。
- 将xml资源输入流对象封装为InputSource,供DocumentLoader加载并解析为Document对象(需要指定Xml解析器,以及XMl格式为标准模式的哪一种(xsd|dtd))。
- 通过Document获取root节点开始解析,在此之前可以通过前置处理器处理(root),在此之后可以通过后置处理器处理(root)。
- 循环解析root下的所有子标签,标签分为默认标签以及自定义标签,处理截然不同。默认标签,例如 bean、import等,自定义标签,例如tx等。
1.2 解析默认标签
DefaultBeanDefinitionDocumentReader#parseDefaultElement
/**
* beans.xsd 默认四种类型 import bean beans alias
* @param ele
* @param delegate
*/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// import 类型处理
// 是加上就是递归调用 加载配置文件定义bean方法
// XMLBeanDefinitionReader.loadBeanDefinitions(resource)
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// alias 处理
// 跟bean中name属性处理相同
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// bean 处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// beans 处理
// 嵌套一不签到没啥大的区别 循环调用 beans 解析过程
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
此方法对各个默认标签进行不同处理,import与beans实则都是递归调用解析过程,所以主要看alias与bean。
bean标签解析
DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 将bean 下的各种 默认属性 等 进行解析 并存放到bdholder对象中
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// bdholder 不为空的情况下查看 是否还有 自定义 属性 并解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
// 解析完成后 bdHolder 中会有这个bean标签的全部信息
try {
// 然后在委托 BeanDefinitionReaderUtils.registerBeanDefinition 进行注册
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 通知此bean已经注册完成
// 为了以后扩展的目前没有实现
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
此方法中BeanDefinitionParserDelegate.parseBeanDefinitionElement对默认标签进行解析,并将解析后的信息保存到BeanDefinitionHolder中
BeanDefinitionParserDelegate#parseBeanDefinitionElement
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;
// id 为null 使用 name 的第一个
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
...
}
// 检查beanName的在bean容器中的唯一性
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 进一步解析bean的其他所有属性 就是一个bean中的所有属性和元素解析成javaBean,即 AbstractBeanDefinition
// xml中的bean有什么 AbstractBeanDefinition 类 就有什么
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
...
// 不存在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);
}
}
...
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
此方法中对bean标签的属性(只是解析id以及name,其他的也是在下面的方法中解析)进行解析,对子标签的解析交给下层进行处理(BeanDefinitionParserDelegate#parseBeanDefinitionElement),对bean下的自定义标签的解析单独处理。
BeanDefinitionParserDelegate#parseBeanDefinitionElement
/**
* 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) {
// 一个集合(LinkedList ) 将正在解析的beanname记录
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);
}
...
// 创建用于承载属性AbstractBeanDefinition类型的GenericBeanDefinition
// BeanDefinition 是配置文件<bean>元素标签在容器中的内部表示形式
// <bean>元素标签拥有
//class scope lazy-init 等配置属性, BeanDefinition 则提供了相应的 beanClass scope lazyInit
//属性, BeanDefinition <bean>中的属性是 一对应的
// Spring 通过 BeanDefinition 将配置文件中的<bea >配置信息转换为容器的内部表示,并将
//这些 BeanDefinition 注册到 BeanDefinitionReistry中。 Spring 容器的 BeanDefinitionRegistrγ 就像
//Spring 配置信息的内存数据库,主要是以 map 的形式保存,后续操作直接从 BeanDefinition Registry 中读取配置信息
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 硬编码解析默认 bean的各种默认属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 一下全部是子元素的 解析
// 提取 description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析 meta 元数据 子元素
// 取出全部meta子元素, 将key-value 封装成 BeanMetadataAttribute对象(还包括)保存到 BeanMetadataAttributeAccessor中
// AbstractBeanDefinition 集成了 BeanMetadataAttributeAccessor
parseMetaElements(ele, bd);
// 解析 lookup-method
// 抽象方法 返回 指定的bean <lookup-method name="getBean" bean="bean"> getBean 为抽象方法
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析 replaced-method
// 与 lookup-method 的区别是 lookup-method自定义 返回的bean ,replaced-method可以将方法的逻辑进行替换
// 都会 封装成 MethodOverride 存放到 bd的methodOverrides中
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析 构造函数参数
parseConstructorArgElements(ele, bd);
// 解析property子元素
parsePropertyElements(ele, bd);
// 解析 qualifier 子元素 作用指定beanName 消除歧义
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
...
return null;
}
此方法首先解析bean标签的class以及parent,然后创建创建默认的AbstractBeanDefinition,然后通过BeanDefinitionParserDelegate#parseBeanDefinitionAttributes解析bean的各种默认属性,然后在此方法中解析其他的子标签(例如lookup-method、property、constructor等)。
BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
/**
* 将给定 bean 元素的属性应用于给定 bean 定义
* Apply the attributes of the given bean element to the given bean * definition.
* @param ele bean declaration element
* @param beanName bean name
* @param containingBean containing bean definition
* @return a bean definition initialized according to the bean element attributes
*/
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 解析 singleton 使用singleton会 提示错误
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
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));
}
// 在嵌入 beanDifinition 情况下且没有单独指定 scope 属性则使用父类默认的属性
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
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
// 非true字符串或空都将是false
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;
}
至此一个bean的默认标签解析工作就完成了,xml中bean标签的所有信息都被封装到了AbstractBeanDefinition对象中。
bean下的自定义标签的解析将单独说明
在DefaultBeanDefinitionDocumentReader#processBeanDefinition中解析完 bean的默认标签以及自定义标签后,需要将保存着bean定义信息的对象(BeanDefinitionHolder),通过DefaultListableBeanFactory#registerBeanDefinition方法注册到Spring容器中。
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
...
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 注册前的最后一次校验,这里的校验不同于之前XML文件校验,
// 主要是对 AbstractBeanDefinition 中 methodOverrides 校验
// 校验 methodOverrides 是否与工厂方法并存或者 methodOverrides 对应的方法根本不存在
((AbstractBeanDefinition) beanDefinition).validate();
}
...
}
// 线程安全的map 所以这里不需要在使用 synchronized
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 通过 beanName 查询的 bean 已经存在
if (existingDefinition != null) {
// 一系列判断
// 是否允许Bean定义重写 检查是否允许覆盖
// 如果对应的 BeanName 已经注册且在配置中配置了 bean 不允许被覆盖,则抛出异常
// 当前要保存的是否和取出来的是一个对象
// 注册beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// bean是否被标记为已创建
// 需要全复制
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
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 {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
// 记录 bean 名称
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
// bean被新的定义覆盖了 或者是 单例
if (existingDefinition != null || containsSingleton(beanName)) {
// 重置给定 bean 的所有 bean 定义缓存,包括从它派生的 bean 缓存
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
至此bean的解析,注册全部完成
import 除去解析特定的几个属性外就是递归调用beans解析过程。
beans 下包含 beans的情况也是递归调用beans的解析过程。
aliase 主要是解析默认属性,并记录别名与beanname的关联关系。
已完成的任务:
-
root下的不同子标签,分别进行解析(import bean beans alias)
-
解析bean标签所有默认属性(class、id等)
-
解析bean标签所有子标签(property等)
-
解析bean下所有自定义标签
-
将承载xml中bean标签全部信息的AbstractBeanDefinition对象注册到Spring 容器(其实就是map,保存到里面)
注意 自定义标签的解析未说明,单独说明。
---- **Cover 《Spring 源码深度解析》**