spring ioc加载

spring ioc容器初始化

ioc容器创建过程:定位、载入、注册

XmlBeanFactory

低级的IOC容器

//根据 Xml 配置文件创建 Resource 资源对象,该对象中包含了 BeanDefinition 的信息
ClassPathResource resource =new ClassPathResource("application-context.xml");
//创建 DefaultListableBeanFactory
DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
//创建 XmlBeanDefinitionReader 读取器,用于载入 BeanDefinition。之所以需要 BeanFactory 作为参数,是因为会将读取的信息回调配置给factory
XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader 执行载入 BeanDefinition 的方法,最后会完成 Bean 的载入和注册。完成后 Bean 就成功的放置到 IOC 容器当中,以后我们就可以从中取得 Bean 来使用
reader.loadBeanDefinitions(resource);

ApplicationContext是高级的ioc容器

FileSystemXmlApplicationContext

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh,
ApplicationContext parent)
throws BeansException {
super(parent); // 为容器设置好 Bean 资源加载器。
setConfigLocations(configLocations); //设置 Bean 定义资源文件的定位路径。
if (refresh) {
refresh(); //载入
}
}
  • AbstractApplicationContext

1.super(parent); 调用父类可以看到初始化spring资源加载器

//获取一个 Spring Source 的加载器用于读入 Spring Bean 定义资源文件
protected ResourcePatternResolver getResourcePatternResolver() {
//AbstractApplicationContext 继承 DefaultResourceLoader,因此也是一个资源加载器
//Spring 资源加载器,其 getResource(String location)方法用于载入资源
return new PathMatchingResourcePatternResolver(this);
}

2.refresh载入
refresh()是一个模板方法,
refresh()方法的作用是:在创建 IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在 refresh 之后使用的是新建立起来的 IOC 容器。refresh 的作用类似于对 IOC 容器的重启,在新建立好的容器中对容器进行初始化,对 Bean 定义资源进行载入。
refresh()方法主要为 IOC 容器 Bean 的生命周期管理提供条件,Spring IOC 容器载入 Bean 定义资源文件从其子类容器的 refreshBeanFactory()方法启动,之后代码都是
注册容器的信息源和生命周期事件

  • AbstractBeanDefinitionReader

loadBeanDefinitions方法

//将指定位置的 Bean 定义资源文件解析为 Spring IOC 容器封装的资源
//加载单个指定位置的 Bean 定义资源文件
Resource resource = resourceLoader.getResource(location);
//委派调用其子类 XmlBeanDefinitionReader 的方法,实现加载功能
int loadCount = loadBeanDefinitions(resource);

此时getResource是资源定位,调用的是 DefaultResourceLoader 中的 getSource()方法定位 Resource

资源载入2个过程:
1.通过调用 XML 解析器将 Bean 定义资源文件转换得到 Document 对象
2. 在完成通用的 XML 解析之后,按照 Spring 的 Bean 规则通过BeanDefinitionReader(DefaultBeanDefinitionDocumentReader)对 Document 对象进行解析,转换为ioc能识别的数据结构BeanDefinition。
3.将BeanDefinition注册到容器中。

  • DefaultBeanDefinitionDocumentReader

元素解析

//使用Spring的Bean规则解析Document元素节点
	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//如果元素节点是<Import>导入元素,进行导入解析
		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);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

解析Bean定义资源Document对象的普通元素

//解析Bean定义资源Document对象的普通元素
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		// 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.
				//todo 注册入口
				//向Spring IOC容器注册解析得到的Bean定义,这是Bean定义向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.
			//在完成向Spring IOC容器注册解析得到的Bean定义之后,发送注册事件
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

对Document对象中Bean元素的解析由BeanDefinitionParserDelegate实现,注册入口BeanDefinitionReaderUtils.registerBeanDefinition。

  • 总结:

IOC容器初始化基本步骤
1.初始化入口容器实现类中refresh()方法
2.在创建 IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,新建容器进行初始化。对 bean 定义载入 IOC 容器使用的方法是 loadBeanDefinition。
大致过程是:通过 ResourceLoader来完成资源文件位置的定位,其中DefaultResourceLoader是默认的实现,可以从类路径,文件系统,URL 等方式来定位资源位置。通过调用 XML 解析器将 Bean 定义资源文件Resource转换得到 Document 对象。通过BeanDefinitionReader(DefaultBeanDefinitionDocumentReader)对 Document 对象进行解析,转换为ioc能识别的数据结构BeanDefinition。
往往使用的是 XmlBeanDefinitionReader 来解析,实际的处理过程是委托给 BeanDefinitionParserDelegate来完成的,从而得到BeanDefinition。最后进行IOC容器注册,就是保存到ConcurrentHashMap。注册的过程中需要线程同步,以保证数据的一致性,以后对bean的所有操作都是围绕这个
ConcurrentHashMap。

  • BeanFactory 和 FactoryBean区别

其中 BeanFactory 指的是 IOC 容器的编程抽象,比如ApplicationContext,XmlBeanFactory 等,这些都是 IOC 容器的具体表现。
FactoryBean 是创建对象的工厂 Bean,只是一个可以在 IOC 容器中被管理的bean,可以看做一个抽象工厂,容器不会返回 FactoryBean 本身,而是返回其生成的对象。Spring 包括了大部分的通用资源和服务访问,都是FactoryBean 的具体实现,其中包括:对 JNDI 查询的处理,对代理对象的处理,对事务性代理的处理,对 RMI 代理的处理等,这些我们都可以看成是具体的工厂,看成是 Spring 为我们建立好的工厂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值