XmlBeanDefinitionReader.doLoadBeanDefinitions
-
- 1.XmlBeanDefinitionReader.doLoadBeanDefinitions方法
- 2.XmlBeanDefinitionReader.doLoadDocument方法
- 3.DefaultDocumentLoader.loadDocument方法
- 4.XmlBeanDefinitionReader.registerBeanDefinitions方法(回到步骤1)
- 5.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions方法
- 6.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
- 7.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
- 8.DefaultBeanDefinitionDocumentReader.processAliasRegistration方法
- 9.DefaultBeanDefinitionDocumentReader.processBeanDefinition方法
- 10.BeanDefinitionReaderUtils.registerBeanDefinition方法
- 11.写在最后
1.XmlBeanDefinitionReader.doLoadBeanDefinitions方法
doLoadBeanDefinitions才开始真正的加载bean定义信息(后续均称之为BeanDefinition)。后续大家会看到很多以do开头的方法,看到这种方法大家就需要重点关注,do开头的方法才是真正干活的。
java
/**
* 将 XML 资源解析为 DOM 文档(Document),并进一步将文档内容转换为
* BeanDefinition 注册到容器中。它是 XML 配置文件解析为 Spring 可
* 管理 Bean 定义的核心
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将XML资源解析为DOM文档对象
Document doc = doLoadDocument(inputSource, resource);
// 从文档中解析并注册Bean定义,返回注册的数量
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
// 抛出BeanDefinitionStoreException异常
catch (BeanDefinitionStoreException ex) {
throw ex;
}
// XML解析时的语法错误(如标签未闭合)
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
// 其他XML解析异常(如DTD/XSD验证失败)
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
// XML解析器配置异常(如不支持的特性)
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
// IO异常(如资源无法读取)
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
// 其他未预期的异常
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
2.XmlBeanDefinitionReader.doLoadDocument方法
这里提一点,由于源码比较复杂。导致大家经常在看到对象属性的时候不知道在哪里赋值的,这个比较重要。所以大家在看源码的时候看到一些赋值的地方更应该重视,可能当时看觉得不起眼,后面这些赋值都是会被用到的。比较重要的属性赋值位置我会在代码里提到
java
/**
* documentLoader解析XML
*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
/**
* getEntityResolver方法,获取EntityResolver,
* 这里entityResolver != null,这里我想说的是这个entityResolver是在哪里被赋值。
* 在上一篇文章中的
* AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法
* beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
*/
protected EntityResolver getEntityResolver() {
// 若实体解析器未初始化,则创建默认实例,实际上这里entityResolver不等于null
if (this.entityResolver == null) {
// 获取资源加载器(通常是当前ApplicationContext)
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
// 若存在资源加载器,使用ResourceEntityResolver
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
// 若不存在资源加载器,使用DelegatingEntityResolver
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
/**
* getValidationModeForResource方法,确定XML资源验证模式
* XML 验证模式:
* VALIDATION_NONE:无验证:不检查 XML 是否符合任何 DTD/XSD 约束,仅解析基本语法
* VALIDATION_DTD:DTD 验证:基于 XML 头部的 DTD 声明(如 <!DOCTYPE beans ...>)验证
* VALIDATION_XSD:XSD 验证:基于 XML 中的 XSD 命名空间(如 xmlns:xsi)验证
* VALIDATION_AUTO:自动检测:未显式指定模式时的默认值,需通过后续逻辑判断
* 最终我们使用的是 VALIDATION_XSD
*/
protected int getValidationModeForResource(Resource resource) {
// 在前面赋值了validationMode = VALIDATION_AUTO
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
// 推断当前验证模式,这里可以自己点进去看下
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// 检测失败时,默认使用XSD验证:通常未检测到DTD声明时,XML更可能使用XSD约束
return VALIDATION_XSD;
}
3.DefaultDocumentLoader.loadDocument方法
java
/**
* XML输入源解析为Document文档对象
*/
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 创建解析器工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
// 创建解析器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
// 解析器解析输入源,返回Document对象,具体的解析源码可自行查看。这里就不在讲解
return builder.parse(inputSource);
}
4.XmlBeanDefinitionReader.registerBeanDefinitions方法(回到步骤1)
java
/**
* 解析XML文档(Document)转换为 BeanDefinition 并注册到 Spring 容器中
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建BeanDefinitionDocumentReader实例(默认实现为DefaultBeanDefinitionDocumentReader)
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 记录注册前容器中已有的BeanDefinition数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 委托文档阅读器解析XML文档并注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回本次新增的BeanDefinition数量(注册后总数 - 注册前总数)
return getRegistry().getBeanDefinitionCount() - countBefore;
}
/**
* XML输入源解析为Document文档对象
*/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
// do开头的方法真正完成注册步骤开始,通过documentElement
doRegisterBeanDefinitions(doc.getDocumentElement());
}
/**
* 在给定的根<beans/>元素中注册每个bean定义
*/
protected void doRegisterBeanDefinitions(Element root) {
// 管理解析代理(delegate)的状态,支持嵌套<beans>标签的递归解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
// 处理<beans>标签的profile属性,实现环境隔离,一般不会设定
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// 检查当前环境是否匹配指定的profile,不匹配则跳过解析
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 解析前的预处理(扩展点)
preProcessXml(root);
// 解析根元素下的所有子元素(核心逻辑),传入根节点<beans>,解析代理
parseBeanDefinitions(root, this.delegate);
// 解析后的后处理(扩展点)
postProcessXml(root);
// 恢复解析代理的状态(支持嵌套解析)
this.delegate = parent;
}
5.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions方法
java
/**
* 解析根元素下的所有子元素(如 <bean>、<import>、<context:component-scan> 等),
* 是真正执行 Bean 定义提取的逻辑
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 这里说明下命名空间:就是我们在application-beans.xml文件中的
// xmlns="http://www.springframework.org/schema/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) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 解析默认命名空间的元素(如<bean>、<import>、<alias>、<beans>)
parseDefaultElement(ele, delegate);
}
else {
// 解析自定义命名空间的元素(如<context:component-scan>)
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 根元素属于自定义命名空间时,直接解析
delegate.parseCustomElement(root);
}
}
6.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
java
/**
* 解析默认命名空间(http://www.springframework.org/schema/beans)标签,
* DefaultBeanDefinitionDocumentReader这里就可以看到大家在xml中配置的各
* 种标签,熟悉的味道
*/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 处理<import>标签:导入其他XML配置文件
// 例如:<import resource="classpath:service.xml"/>
importBeanDefinitionResource(ele);
}
// 处理<alias>标签:为已注册的Bean定义别名
// 例如:<alias name="userService" alias="userServiceAlias"/>
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 处理<bean>标签:解析并注册Bean定义(核心逻辑)
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 处理<beans>标签:递归解析嵌套的配置
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 递归调用doRegisterBeanDefinitions解析嵌套的<beans>
// 递归到本类中的doRegisterBeanDefinitions(Element root)
// spring中很多递归都不是简单的递归本方法,这点需要注意
doRegisterBeanDefinitions(ele);
}
}
7.DefaultBeanDefinitionDocumentReader.parseDefaultElement方法
java
/**
* 解析 <import> 标签的 resource 属性,定位并加载目标配置文件,
* 将其中的 Bean 定义合并到当前容器中。
* 例如:<import resource="classpath:service.xml"/>
*/
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);
// 判断路径是否为绝对路径(URL或绝对URI)
boolean absoluteLocation = false;
try {
// 若路径是URL(如file:、http:)或绝对URI,则视为绝对路径
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// 无法转换为URI时,视为相对路径(除非是classpath*:前缀)
}
// 处理绝对路径资源
if (absoluteLocation) {
try {
// 加载绝对路径资源中的Bean定义,返回加载数量
// 这里又调用到上一篇中的AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)方法中,可以理解成递归了
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isTraceEnabled()) {
logger.trace("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;
// 创建相对于当前资源的相对资源(如当前文件在classpath:spring/下,导入"service.xml"则定位到classpath:spring/service.xml)
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
// 相对资源存在时,直接加载
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
else {
// 相对资源不存在时,基于当前资源的URL构建绝对路径
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isTraceEnabled()) {
logger.trace("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[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
8.DefaultBeanDefinitionDocumentReader.processAliasRegistration方法
java
/**
* 解析 <alias> 标签的 name 和 alias 属性,验证其合法性,将别名注册到容器中,
* 并发布别名注册事件
*/
protected void processAliasRegistration(Element ele) {
// 提取<alias>标签的name和alias属性
String name = ele.getAttribute(NAME_ATTRIBUTE);
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 {
// 调用SimpleAliasRegistry注册别名,这里的getRegistry返回的就是在前面
// AbstractRefreshableApplicationContext.refreshBeanFactory()中
// DefaultListableBeanFactory beanFactory = createBeanFactory();
// 创建的DefaultListableBeanFactory它继承了SimpleAliasRegistry
// 它内部维护了一个ConcurrentHashMap,别名到名称的映射关系,这里可以自己点进去看
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));
}
}
9.DefaultBeanDefinitionDocumentReader.processBeanDefinition方法
这里大概讲解一下下面涉及到的一些知识点
GenericBeanDefinition:
Spring 解析 标签或 @Bean 注解时,首先生成 GenericBeanDefinition,再根据是否有父定义决定是否合并为 RootBeanDefinition,支持动态修改,可以理解成是BeanDefinition的一个中间态
RootBeanDefinition:
表示完全合并后的 Bean 定义,是 Spring 容器最终用于创建 Bean 实例的元数据。它通常是通过合并父 Bean 定义(parentName)和子 Bean 定义后生成的,不依赖其他 Bean 定义
lookup-method:
用于动态替换 Bean 中的抽象方法,使其返回指定的目标 Bean 实例。它的核心场景是:在单例 Bean 中获取原型(prototype)Bean------ 由于单例 Bean 初始化时仅创建一次,若直接在单例 Bean 中注入原型 Bean,后续每次使用的都是同一个原型实例;而通过 lookup-method 可确保每次调用方法时都获取到新的原型实例
lookup-method原理:
通过 CGLIB 动态代理 生成目标 Bean 的子类,重写 lookup-method 配置的抽象方法,在方法体内从 Spring 容器中获取指定的目标 Bean 并返回。
replaced-method:
用于完全替换 Bean 中的某个方法,即调用目标方法时,实际执行的是自定义的 "方法替换器" 逻辑,而非原方法逻辑。它的核心场景是:在不修改目标类源码的前提下,重写方法的实现(如修复旧代码的 bug、增强方法功能)。
replaced-method原理:
通过 MethodReplacer 接口 定义替换逻辑,在 Bean 初始化时,将自定义的 MethodReplacer 实例与目标方法关联。通过 CGLIB 生成目标 Bean 的代理类,重写目标方法,在代理方法中调用 MethodReplacer 的 reimplement 方法执行替换逻辑。
java
/**
* 将 <bean> 标签解析为 BeanDefinition 及其元数据(名称、别名等),经过装饰增强后
* 注册到容器,并发布注册事件
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析<bean>标签,生成包含BeanDefinition、名称和别名的封装对象(核心)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 若需要,装饰BeanDefinition(如处理自定义属性或嵌套标签)
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将最终装饰后的BeanDefinition注册到容器
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));
}
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
/**
* 上面方法的重载
* 解析 <bean> 标签的 id 和 name 属性以确定 Bean 名称和别名,校验名称唯一性,
* 生成 BeanDefinition 实例,并最终封装为 BeanDefinitionHolder
*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 提取<bean>标签的id和name属性
String id = ele.getAttribute(ID_ATTRIBUTE);
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));
}
// 确定Bean的主名称(beanName)
String beanName = id;
// 若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");
}
}
// 校验Bean名称和别名的唯一性
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 解析<bean>标签的其他属性(如class、scope等),生成AbstractBeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 若主名称仍为空(id和name均未指定),自动生成Bean名称
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
// 嵌套Bean(如<bean><property><bean/></property></bean>),生成内部名称
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
// 顶级Bean,通过readerContext生成名称
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;
}
}
// 将别名列表转换为数组,封装为BeanDefinitionHolder返回
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
// 若解析失败(如缺少class属性),返回null
return null;
}
/**
* 上面方法的重载
*/
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
// 记录解析状态(用于错误信息定位,如嵌套解析时的层级)
this.parseState.push(new BeanEntry(beanName));
// 提取class和parent属性
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 创建基础的BeanDefinition实例(GenericBeanDefinition)
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析<bean>标签的核心属性(scope、lazy-init等)
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 解析description子元素(Bean描述信息)
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析各类子元素,完善BeanDefinition
// <meta>标签:元数据(键值对),这里可以自行点进去查看具体的解析逻辑
parseMetaElements(ele, bd);
// <lookup-method>:方法查找注入,这里可以自行点进去查看具体的解析逻辑
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// <replaced-method>:方法替换,这里可以自行点进去查看具体的解析逻辑
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// <constructor-arg>:构造器注入,这里可以自行点进去查看具体的解析逻辑
parseConstructorArgElements(ele, bd);
// <property>:setter属性注入,这里可以自行点进去查看具体的解析逻辑
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;
}
10.BeanDefinitionReaderUtils.registerBeanDefinition方法
回到第9步processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
BeanDefinitionHolder:
统一封装 BeanDefinition 实例、Bean 的主名称(beanName)和别名(aliases),确保这三者在传递和处理过程中不会分离
BeanDefinition容器:
DefaultListableBeanFactory中维护的beanDefinitionMap
BeanDefinition名称容器:
DefaultListableBeanFactory中维护的beanDefinitionNames
java
/**
* 将 BeanDefinitionHolder 中封装的 Bean 主名称、BeanDefinition 和别名,
* 分别注册到 BeanDefinitionRegistry 中
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 通过Bean的主名称,注册BeanDefinition到BeanDefinition容器中
// 里面也会注册BeanDefinition名称到BeanDefinition名称容器中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 若存在别名,为每个别名注册与主名称的映射
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// 同第8步getReaderContext().getRegistry().registerAlias(name, alias);
registry.registerAlias(beanName, alias);
}
}
}
11.写在最后
以上主要讲解了spring默认命名空间标签的解析,自定义标签解析请看下篇文章。