首页 > 其他分享 >Spring5 IOC容器解析——XML配置的资源定位、加载、解析、注册分析

Spring5 IOC容器解析——XML配置的资源定位、加载、解析、注册分析

时间:2023-01-07 18:33:19浏览次数:66  
标签:XML 容器 Bean loadBeanDefinitions 解析 IOC public 加载

从FileSystemXmlApplicationContext开始

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);

由上面的入口进入到构造方法中

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}

public FileSystemXmlApplicationContext(
		String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
		throws BeansException {

	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
		//从此处开始IOC容器的初始化
		refresh();
	}
}

设置好配置资源的路径之后,就会调用refresh()方法进行容器的初始化

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {

	/**
	 * 加载或刷新一个持久化的配置,可能是XML文件、属性文件或关系数据库模式。
	 * 由于这是一种启动方法,如果失败,应该销毁已经创建的单例,以避免悬空资源。
	 * 换句话说,在调用该方法之后,要么全部实例化,要么完全不实例化。
	 * @throws 如果bean工厂无法初始化,则抛出 BeansException 异常
	 * @throws 如果已经初始化且不支持多次刷新,则会抛出 IllegalStateException 异常
	 */
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		// 给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
		synchronized (this.startupShutdownMonitor) {
			// 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
			prepareRefresh();

			//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
			//子类的refreshBeanFactory()方法启动,里面有抽象方法
			//针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 注册一些容器中需要的系统Bean.例如classloader,beanfactoryPostProcessor等
			prepareBeanFactory(beanFactory);

			try {
				//允许容器的子类去注册postProcessor  ,钩子方法
				postProcessBeanFactory(beanFactory);

				// 激活在容器中注册为bean的BeanFactoryPostProcessors
				//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
				//方法扫描应用中所有BeanDefinition并注册到容器之中
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册拦截bean创建过程的BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// 找到“messageSource”的Bean提供给ApplicationContext使用,
				// 使得ApplicationContext具有国际化能力。
				initMessageSource();

				// 初始化ApplicationEventMulticaster该类作为事件发布者,
				// 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
				initApplicationEventMulticaster();

				// 预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,
				// 该方法需要在所有单例 bean 初始化之前调用
				// 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
				onRefresh();

				// 注册监听器(检查监听器的bean并注册它们)
				registerListeners();

				//设置自定义的类型转化器ConversionService,
				// 设置自定义AOP相关的类LoadTimeWeaverAware,
				// 清除临时的ClassLoader
				// ,实例化所有的类(懒加载的类除外)
				finishBeanFactoryInitialization(beanFactory);

				// 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用扩展了SmartLifecycle接口的start方法
				// 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
				// 并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				//销毁已创建的Bean
				destroyBeans();

				// Reset 'active' flag.
				//取消refresh操作,重置容器的同步标识
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// 重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了……
				resetCommonCaches();
			}
		}
	}
}

AbstractApplicationContext的refresh()方法是容器刷新都会执行的方法,在refresh()方法里面配置的解析逻辑都在obtainFreshBeanFactory()方法中进行。

跟进obtainFreshBeanFactory方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	//调用子类容器的refreshBeanFactory()刷新子类容器
	refreshBeanFactory();
	return getBeanFactory();
}

跟进refreshBeanFactory()方法,该方法由其子类AbstractRefreshableApplicationContext提供

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

	@Override
	protected final void refreshBeanFactory() throws BeansException {
		//如果已经有容器,销毁容器中的bean,关闭容器
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//创建容器
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			//对容器进行定制化,默认主要设置是否允许BeanDefinition的重复注册,
			// Bean之间是否允许循环引用等,此外还可以设置启动参数,开启注解的自动装配等
			customizeBeanFactory(beanFactory);
			//加载BeanDefinition,for xml,使用了委派模式
			loadBeanDefinitions(beanFactory);
			//将 BeanFactory 设置为 Spring 容器的内部 BeanFactory
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
}

xml方式加载BeanDefinition,跟进loadBeanDefinitions(beanFactory)

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 1、为给定的BeanFactory创建一个新的XmlBeanDefinitionReader
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		// 2、设置 BeanDefinitionReader 的相关属性
		// 2.1.设置 Environment,即环境,与容器的环境一致
		beanDefinitionReader.setEnvironment(this.getEnvironment());

		// 2.2.设置 ResourceLoader,即资源加载器,因为容器实现了该接口,具体加载资源的功能
		beanDefinitionReader.setResourceLoader(this);
		// 2.3.设置 EntityResolver,即实体解析器,这里用于解析资源加载器加载的资源内容
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		// 3.初始化 BeanDefinitionReader ,空方法,允许子类提供阅读器的自定义初始化
		// 钩子方法,允许子类在加载bean definition之前进一步设置XmlBeanDefinitionReader
		// ->比如,更改XmlBeanDefinitionReader自己提供的DocumentLoader
		// 或者BeanDefinitionDocumentReader等默认对象
		initBeanDefinitionReader(beanDefinitionReader);
		// 4.通过 BeanDefinitionReader 加载 Bean
		loadBeanDefinitions(beanDefinitionReader);
	}
}

观察代码,该方法的主要目的是创建了BeanDefinitionReader ,并由它去加载 Bean。其过程如下:

  • 创建 BeanDefinitionReader
  • 设置 BeanDefinitionReader 的相关属性
  • 初始化 BeanDefinitionReader
  • 通过 BeanDefinitionReader 加载 Bean

通过 BeanDefinitionReader 加载 Bean

在创建完 BeanDefinitionReader 后,则就需要通过它来 加载 Bean,接着跟进loadBeanDefinitions(beanDefinitionReader)方法

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
}

接着跟进reader.loadBeanDefinitions(configLocations)

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

	@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {
			count += loadBeanDefinitions(location);
		}
		return count;
	}
}

根据locations逐个调用loadBeanDefinitions(location)加载

通过 Location 加载 Bean

加载的 Bean 的责任被交给了 BeanDefinitionReader ,下面来看看该类的 loadBeanDefinitions 方法。在跟进loadBeanDefinitions(String location)方法

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

	@Override
	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}

	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		// 1.取得资源加载器,即容器本身
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		// 判断资源加载器类型
		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
			// 说明该 ResourceLoader 可以基于路径加载多个资源
			try {
				// 2.加载资源
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 3.通过 Resource 加载 Bean
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				return count;
			}
			catch (IOException ex) {
				throw new BeanDefinitionStoreException(
						"Could not resolve bean definition resource pattern [" + location + "]", ex);
			}
		}
		else {
			// Can only load single resources by absolute URL.
			// 表示 ResourceLoader 只能加载一个资源
			Resource resource = resourceLoader.getResource(location);
			int count = loadBeanDefinitions(resource);
			if (actualResources != null) {
				actualResources.add(resource);
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
			}
			return count;
		}
	}
}

该方法的工作流程:

  • 取得资源加载器
  • 加载资源,通过 location 利用 ResourcePatternResolver加载
  • 通过 Resource 加载 Bean

接着在跟进loadBeanDefinitions(resources)方法

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {

	@Override
	public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
		Assert.notNull(resources, "Resource array must not be null");
		int count = 0;
		for (Resource resource : resources) {
			count += loadBeanDefinitions(resource);
		}
		return count;
	}
}

通过 Resource 加载 Bean

在得到资源(Resource)后,该方法对它进行了封装,使其变成一个 EncodedResource 对象。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
	@Override
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		// EncodedResource 表示编码类型的资源
		return loadBeanDefinitions(new EncodedResource(resource));
	}
}

通过 EncodedResource 加载 Bean

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Loading XML bean definitions from " + encodedResource);
		}

		// 1.取得[已加载的资源]的集合,用于存在已加载的资源。空,则创建。
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		// 2.将当前资源加入集合
		if (!currentResources.add(encodedResource)) {
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		// 3.将资源转换成流
		try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
			//5.通过流创建 InputSource ,并设置编码
			InputSource inputSource = new InputSource(inputStream);
			if (encodedResource.getEncoding() != null) {
				inputSource.setEncoding(encodedResource.getEncoding());
			}
			//6.调用同类方法,通过 InputSource 加载 Bean
			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally {
			// 移除已完成解析的资源
			currentResources.remove(encodedResource);
			// 集合为空,则一并删除
			if (currentResources.isEmpty()) {
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
}

加载步骤:

  • 1、取得已加载的资源集合
  • 2、将当前资源添加到集合
  • 3、将资源转换成流
  • 4、通过流创建 InputSource ,并设置编码
  • 5、通过 InputSource 加载 Bean

通过 InputSource 加载 Bean

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			// 1.解析 XML 文件
			//创建Document对象,XML的文档对象,就是dom树
			// 使用这个Document可以获取XML文件中的节点并且创建节点
			// SAX XML
			//将InputSource转换为DOM对象,解析过程由documentLoader实现
			Document doc = doLoadDocument(inputSource, resource);
			// 2.注册 Bean
			//解析dom树,即解析出一个个属性,将其保存到BeanDefinition当中
			//并向容器注册BeanDefinition
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		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);
		}
	}
}

解析并注册 BeanDefinitions

将文件装换为Document以后,接下来的提取以及注册Bean就是我们的重头戏。 上一步中 XmlBeanDefinitionReader 已经取得了 XML 的 Document 对象,完成了资源的解析过程。

 

下一步就是 Bean 的注册过程。

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//创建BeanDefinitionDocumentReader,这个是实际从XML的DOM树中读取BeanDefiniton
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//获取注册表beanDefinitionMap的在本次加载前的BeanDefinition数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		//加载并注册
		//这里使用到了单一职责原则,将逻辑处理委托给单一的类进行处理,这个逻辑处理类就是 BeanDefinitionDocumentReader 对象
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//本次加载注册后容器里BeanDefinition的数量减去先前的,即本次加载的BeanDefinition数量
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
}

继续深入registerBeanDefinitions方法:

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}
}

继续深入doRegisterBeanDefinitions方法:doRegisterBeanDefinitions算开始真正解析XML文件了。

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

	protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		//BeanDefinition解析委托类
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		//判断这个根节点是否是默认的命名空间
		//底层就是判断这个根节点的NamespaceUrl=="http://www.springframework.org/schema/beans"
		if (this.delegate.isDefaultNamespace(root)) {
			//获取这个profile属性的值,表示剖面,用于设置环境
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				//根据分隔符换换成数组
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				// We cannot use Profiles.of(...) since profile expressions are not supported
				// in XML config. See SPR-12458 for details.
				//判断这个切面是否是激活的环境,如果不是直接返回,表示这个配置文件不是当前运行环境的配置文件
				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;
				}
			}
		}
		//在解析xml之前做的准备工作,其实什么也没做
		//空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析前做一些处理,可以实现此方法
		preProcessXml(root);
		//调用这个方法,解析
		parseBeanDefinitions(root, this.delegate);
		//后续处理的
		//空代码留给子类去实现 模板设计模式 继承 DefaultBeanDefinitionDocumentReader 的子类在XML解析后做一些处理,可以实现此方法
		postProcessXml(root);

		this.delegate = parent;
	}
}

继续深入parseBeanDefinitions(root, this.delegate),进入到真正的解析逻辑里面对BeanDefinition进行解析

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		//如果是默认的命名空间
		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;
					//Bean定义的Document对象使用了Spring默认的XML命名空间,如http://www.springframework.org/schema/beans
					if (delegate.isDefaultNamespace(ele)) {
						//若是则按照spring原有的逻辑进行解析
						parseDefaultElement(ele, delegate);
					}
					else {
						//否则使用扩展的自定义代理类进行解析
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//使用扩展的自定义代理类进行解析
			delegate.parseCustomElement(root);
		}
	}
}

继续深入parseDefaultElement(ele, delegate),此方法会完成对标签的解析

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//如果元素节点是<Import>导入元素,进行导入解析
		//<import resource="classpath:applicationContext-datasource.xml" />
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//如果元素节点是<Alias>别名元素,进行别名解析
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,
		//按照Spring的Bean规则解析元素
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//解析beans,递归调用doRegisterBeanDefinitions
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}
}

继续深入processBeanDefinition(ele, delegate),此方法会真正解析出BeanDefinition

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类
		//对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				//向Spring IOC容器注册解析得到的BeanDefinition,这是BeanDefinition向IOC容器注册的入口
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			// 在完成BeanDefinition注册之后,往容器发送注册完成的事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}
}
  • 由BeanDefinitionParserDelegate将解析出来的BeanDefinition封装到BeanDefinitionHolder中。
  • 由BeanDefinitionReaderUtils的registerBeanDefinition方法将BeanDefinition注册到Spring IOC容器中。
  • 最终调用DefaultListableBeanFactory类的registerBeanDefinition方法将beanDefinition注册到beanDefinitionMap中。

以上便是资源定位、加载、解析、注册的整个流程。

XML配置方式的BeanDefinition注册流程:

  • 1、在FileSystemXmlApplicationContext的构造函数中设置配置资源的路径,接着调用refresh()方法进行容器的初始化。
  • 2、refresh方法中的obtainFreshBeanFactory()方法进行配置的解析逻辑。
  • 3、调用子类容器的refreshBeanFactory()刷新子类容器。
  • 4、在AbstractRefreshableApplicationContext类的refreshBeanFactory方法中创建DefaultListableBeanFactory实例。
  • 5、将DefaultListableBeanFactory实例作为参数传入到loadBeanDefinitions方法中。
  • 6、在loadBeanDefinitions方法中通过DefaultListableBeanFactory创建XmlBeanDefinitionReader实例。
  • 7、在loadBeanDefinitions方法中设置ResourceLoader用于加载资源,(即容器实例,容器实现了ResourceLoader接口)
  • 8、通过BeanDefinitionReader加载Bean资源。
  • 9、通过ResourcePatternResolver来加载资源,并通过EncodedResource包装资源实例。
  • 10、XmlBeanDefinitionReader类的doLoadBeanDefinitions通过 InputSource加载Bean。
  • 11、XmlBeanDefinitionReader类的doLoadDocument方法将xml解析成Document对象。
  • 12、XmlBeanDefinitionReader类的registerBeanDefinitions方法创建BeanDefinitionDocumentReader实例。
  • 13、在BeanDefinitionDocumentReader类的registerBeanDefinitions方法中,从Document对象中解析并注册BeanDefiniton。
  • 14、DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions方法通过参数BeanDefinitionParserDelegate解析BeanDefinition。
  • 15、DefaultBeanDefinitionDocumentReader类的parseDefaultElement按照spring原有的逻辑进行解析。
  • 16、通过BeanDefinitionParserDelegate的parseBeanDefinitionElement解析出包含了BeanDefinition实例的BeanDefinitionHolder包装实例。
  • 17、通过BeanDefinitionReaderUtils类的registerBeanDefinition方法将BeanDefinition实例注册到容器中,如果BeanDefinition是单例的化,之前已经注册过了的,就需要清空之前的注册信息。
  • 18、使用beanName做唯一标识注册到DefaultListableBeanFactory类中的beanDefinitionMap中,有别名注册别名。

参考: https://www.cnblogs.com/moxiaotao/p/9349536.html

https://www.cnblogs.com/histlyb/p/8976635.html

标签:XML,容器,Bean,loadBeanDefinitions,解析,IOC,public,加载
From: https://blog.51cto.com/u_14014612/5995705

相关文章