Spring IOC源码篇五 核心方法obtainFreshBeanFactory.doLoadBeanDefinitions

XmlBeanDefinitionReader.doLoadBeanDefinitions

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默认命名空间标签的解析,自定义标签解析请看下篇文章。

相关推荐
凸头2 小时前
解决慢SQL问题
java·mysql
脑壳疼___3 小时前
若依 springboot websocket
java·spring
咖啡教室4 小时前
程序员应该掌握的网络命令telnet、ping和curl
运维·后端
你的人类朋友5 小时前
Let‘s Encrypt 免费获取 SSL、TLS 证书的原理
后端
老葱头蒸鸡5 小时前
(14)ASP.NET Core2.2 中的日志记录
后端·asp.net
失散135 小时前
分布式专题——23 Kafka日志索引详解
java·分布式·云原生·架构·kafka
西红柿维生素5 小时前
CPU核心数&线程池&设计模式&JUC
java
云虎软件朱总5 小时前
配送跑腿系统:构建高并发、低延迟的同城配送系统架构解析
java·系统架构·uni-app
18538162800余+5 小时前
深入解析:什么是矩阵系统源码搭建定制化开发,支持OEM贴牌
java·服务器·html