BeanDefinition的Resource定位分析(六)

1.概述

通过源码我们发现,资源的定位问题主要发生在容器初始化过程中完成的,FileSystemXmlApplicationContextClassPathXmlApplicationContext 在一个构造器函数中执行refresh()容器启动的过程中完成的,当然这边启动过程中容器会有大量的复杂的初始化操作,资源的定位只是其中的一小环节。下面我们就FileSystemXmlApplicationContext 为例介绍Resource资源定位过程分析。

2.ApplicationContext集成体系介绍

ApplicationContext集成体系
这里我们需要重点关注的是AbstractRefreshableApplicationContext的refreshBeanFactory方法的实现,refreshBeanFactory()方法被FileSystemXmlApplicationContext构造函数中的refresh()调用。在这个方法中,通过createBeanFactory()构建了一个IoC容器供ApplicationContext使用。这个IoC容器就是我们前面提到过的DefaultListableBeanFactory,同时,它启动了loadBeanDefinitions()来载入BeanDefinition,这个过程和前面以编程的方式来使用IoC容器(XmlBeanFacoty)的过程非常类似。

3.源码分析:

我们就资源定位和加载的核心代码拿出来分析:


	/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		/// 这里判断,如果已经建立了BeanFactory,则销毁并关闭该BeanFactory
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// 这里是创建并设置持有的DefaultListableBeanFactory的地方
           // 同时调用loadBeanDefinitions载入BeanDefinition的信息
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			// 资源就是在此处定位并加载的
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

我们找到loadBeanDefinitions(beanFactory)方法,此方法中完成了资源的定位和加载,主要执行如下代码:

protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;

我们可以看到在AbstractRefreshableApplicationContext抽象类中它只是提供了一个抽象的模板方法,具体实现由不同的子类去覆盖实现,这边我们主要是通过FileSystemXmlApplicationContext为例分析,所以我们找到相关的实现是在AbstractXmlApplicationContext中去实现的:

	/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 为相应的BeanFactory创建XmlBeanDefinitionReader(后续xml元信息的解析就依靠此类完成)
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		// 环境变量设置
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		// 设置ResourceLoader,这边传this是因为在容器继承链中是继承了DefaultResourceLoader的
		// AbstractApplicationContext 继承了DefaultResourceLoader
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		// 加载资源
		loadBeanDefinitions(beanDefinitionReader);
	}

AbstractXmlApplicationContext#loadBeanDefinitions(beanDefinitionReader)方法中实现了真正的资源定位和加载:


	/**
	 * Load the bean definitions with the given XmlBeanDefinitionReader.
	 * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}
	 * method; hence this method is just supposed to load and/or register bean definitions.
	 * @param reader the XmlBeanDefinitionReader to use
	 * @throws BeansException in case of bean registration errors
	 * @throws IOException if the required XML document isn't found
	 * @see #refreshBeanFactory
	 * @see #getConfigLocations
	 * @see #getResources
	 * @see #getResourcePatternResolver
	 */
	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
	   // 获取子类覆盖实现的资源
		Resource[] configResources = getConfigResources();
		// 加载资源
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 获取子类中设置的资源数组的资源路径URL
		String[] configLocations = getConfigLocations();
		//实现加载
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

从代码中我们可以看到String[] configLocations = getConfigLocations(); 资源路径的获取是在这边调用的,如果子类覆盖可此实现,那么我们直接可以从子类中获取到相应的资源文件。反过来看我们从FileSystemXmlApplicationContext中去看,在FileSystemXmlApplicationContext中确实是覆盖了getConfigLocations();方法。

微信公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BeanDefinitionSpring中的一个核心概念,它表示了一个Bean的定义。在Spring中,根据BeanDefinition来创建Bean对象。BeanDefinition具有很多属性用来描述Bean的信息和配置。 AnnotatedBeanDefinition是AnnotatedBeanDefinition接口的实现类,表示注解的BeanDefinition。它包含了注解元数据和基本类元数据的信息。AnnotatedBeanDefinition有两个主要的实现类:AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition。 RootBeanDefinition代表普通的BeanDefinition实现,通过直接实例化BeanDefinition对象来创建。ChildBeanDefinition代表可以设置父BeanDefinition的子BeanDefinition。GenericBeanDefinition代表一般的BeanDefinition,AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition都是它的两个主要实现类。 综上所述,BeanDefinitionSpring中用来描述Bean的定义的概念,它包含了Bean的各种属性和配置信息。AnnotatedBeanDefinition是注解的BeanDefinition的实现类,它包含了注解元数据和类元数据的信息。RootBeanDefinition和ChildBeanDefinitionBeanDefinition的不同实现方式,GenericBeanDefinition是一般的BeanDefinition,它的两个主要实现类是AnnotatedGenericBeanDefinition和ScannedGenericBeanDefinition。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [BeanDefinition](https://blog.csdn.net/xxssyyyyssxx/article/details/124819785)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值