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

相关推荐
paishishaba15 分钟前
JAVA面试复习笔记(待完善)
java·笔记·后端·面试
Victor3561 小时前
Redis(72)Redis分布式锁的常见使用场景有哪些?
后端
四谎真好看1 小时前
Java 黑马程序员学习笔记(进阶篇19)
java·笔记·学习·学习笔记
Victor3561 小时前
Redis(73)如何处理Redis分布式锁的死锁问题?
后端
從南走到北1 小时前
JAVA代泊车接机送机服务代客泊车系统源码支持小程序+APP+H5
java·开发语言·微信小程序·小程序
程序员爱钓鱼3 小时前
Python编程实战 · 基础入门篇 | Python的缩进与代码块
后端·python
earthzhang20216 小时前
第3讲:Go垃圾回收机制与性能优化
开发语言·jvm·数据结构·后端·性能优化·golang
apocelipes7 小时前
golang unique包和字符串内部化
java·python·性能优化·golang
Full Stack Developme7 小时前
java.text 包详解
java·开发语言·python