IOC原理之IoC容器的初始化过程
IoC容器的初始化过程包括Resource定位、BeanDefinition的载入以及向IoC容器注册这些BeanDefinition三个阶段。仍以FileSystemXmlApplicationContext为例,来讲解这个过程。FileSystemXmlApplicationContext的继承体系:由继承关系可知,FileSystemXmlApplicationCon...
IoC容器的初始化过程包括
Resource定位
、BeanDefinition的载入
以及向IoC容器注册这些BeanDefinition
三个阶段。
IoC容器的初始化过程概要
IoC容器的初始化包括三个过程:
第一个过程是 Resource定位 过程。这个Resource定位指的是BeanDefinition的资源定位,它由
ResourceLoader
通过统一的Resource
接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口。比如.在文件系统中的Bean定义信息可以使用FileSystemResource
来进行抽象。在类路径中的Bean定义信息可以使用ClassPathResource
来进行抽象等等。这个定位过程类似于容器寻找数据的过程,就像用水捅装水先要把水找到一样。第二个过程是 BeanDefinition的载入 。这个载入过程是把用户定义好的
Bean
表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition
。下面介绍这个数据结构的详细定义。具体来说,这个BeanDefinition实际上就是POJO对象在IoC容器中的抽象。通过这个BeanDefinition定义的数据结构,使IoC容器能够方便地对Polo对象也就是Bean进行管理。第三个过程是 向IoC容器注册这些Bean Definition 的过程。这个过程是通过调用
BeanDefinitionRegistry
接口的实现来完成的。这个注册过程把载人过程中解析得到的BeanDeftnition向IoC容器进行注册。在IoC容器内部将BeanDefinition注人到一个HashMap
中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。
几个常用的ApplicationContext
1. FileSystemXmlApplicationContext
FileSystemXmlApplicationContext的继承体系:
由继承关系可知,FileSystemXmlApplicationContext
通过继承AbstractApplicationContext
具备了DefaultResourceLoader
读取Resource
定义的BeanDefinition
的能力。因为AbstractApplicationContext
的基类是DefaultResourceLoader
。
看看其完整继承体系:
2. ClassPathXmlApplicationContext
ClassPathXmlApplicationContext的继承体系:
由继承关系可知,ClassPathXmlApplicationContext
通过继承AbstractApplicationContext
具备了DefaultResourceLoader
读取Resource
定义的BeanDefinition
的能力。因为AbstractApplicationContext
的基类是DefaultResourceLoader
。和上面的FileSystemXmlApplicationContext
如出一辙。
看看其完整继承体系:
3. AnnotationConfigApplicationContext
AnnotationConfigApplicationContext的继承体系:
可以看到,AnnotationConfigApplicationContext
,也是通过DefaultResourceLoader
读取Resource
。
看看其完整继承体系:
详细分析IoC初始化过程
以常用的ClassPathXmlApplicationContext
为例:
1、 新建resources/META-INF/spring/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.source.IoC.domain.User">
<property name="name" value="张三"/>
</bean>
</beans>
2、 新建User
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3、
public static void main(String args[]) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setConfigLocation("classpath:/META-INF/spring/context.xml");
applicationContext.refresh();
User user = applicationContext.getBean("user", User.class);
System.out.printf("user.getName() = %s \n", user.getName());
}
运行main方法,整个运行过程如下:
所以这里主要要来看一看AbstractApplicationContext
中的refresh()
这个函数:
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
//这里是在子类中启动refreshBeanFactory()定位并载入
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//prepare the bean factory for use in this context
this.prepareBeanFactory(beanFactory);
try {
//设置BeanFactory的后置处理
this.postProcessBeanFactory(beanFactory);
//调用BeanFactory的后处理器,这些后处理器是在Bean定义中想容器注册的
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册Bean后处理器,在Bean创建过程中调用
this.registerBeanPostProcessors(beanFactory);
//对上下文中的消息源进行初始化
this.initMessageSource();
//初始化上下文中的事件机制
this.initApplicationEventMulticaster();
//初始化其他的特殊Bean
this.onRefresh();
//检查监听Bean并且将这些Bean向容器注册
this.registerListeners();
//实例化所有的(non-lazy-init)单件
this.finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束Refresh过程
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
//为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件Bean
this.destroyBeans();
//重置'active'标志
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
这个obtainFreshBeanFactory
很关键,这里面有 IoC的Resource定位和载入:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//资源定位和载入,是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法
this.refreshBeanFactory();
//getBeanFactory是一个抽象方法,在子类AbstractRefreshableApplicationContext中实现的方法
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
看看refreshBeanFactory()
源码如下:
protected final void refreshBeanFactory() throws BeansException {
//这里判断,如果建立了BeanFactory,则销毁并关闭该BeanFactory
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//这里的创建并设置持有的DefaultListableBeanFactor的地方
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
//载入Bean ,抽象方法,委托子类AbstractXmlApplicationContext实现
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
看看子类AbstractXmlApplicationContext
中实现的loadBeanDefinitions
:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = this.getConfigResources(); //只可能为null
if (configResources != null) { //不会走这一条路 参数类型Resource...
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = this.getConfigLocations();
if (configLocations != null) { // 参数类型String...
reader.loadBeanDefinitions(configLocations);
}
}
@Nullable
protected Resource[] getConfigResources() {
return null;
}
继续往下看AbstractBeanDefinitionReader
流操作类的loadBeanDefinitions
,这里的流操作来实现IoC的载入:
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
String[] var3 = locations;
int var4 = locations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
counter += this.loadBeanDefinitions(location); //调用下面的函数
}
return counter;
}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(location, (Set)null); //调用下面的函数
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = this.getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int loadCount;
if (!(resourceLoader instanceof ResourcePatternResolver)) {
Resource resource = resourceLoader.getResource(location);
loadCount = this.loadBeanDefinitions((Resource)resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
} else {
try {
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
loadCount = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Resource[] var6 = resources;
int var7 = resources.length;
for(int var8 = 0; var8 < var7; ++var8) {
Resource resource = var6[var8];
actualResources.add(resource);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
} catch (IOException var10) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
}
}
}
}
loadBeanDefinitions
会调用DefaultResourceLoader
中的getResource
:
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
Iterator var2 = this.protocolResolvers.iterator();
Resource resource;
do {
if (!var2.hasNext()) {
if (location.startsWith("/")) {
return this.getResourceByPath(location);
}
if (location.startsWith("classpath:")) {
return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
}
try {
URL url = new URL(location);
return (Resource)(ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
} catch (MalformedURLException var5) {
return this.getResourceByPath(location);
}
}
ProtocolResolver protocolResolver = (ProtocolResolver)var2.next();
resource = protocolResolver.resolve(location, this);
} while(resource == null);
return resource;
}
可以看到,getResource
又调用了子类实现的getResourceByPath
方法或是子类传递过来的字符串,实现 Resource定位
整个过程就说得通了。总结起来就是,Resource资源通过最外层的实现类传进来的字符串或者直接调用getResourceByPath
方法,来获取bean资源路径,然后通过AbstractBeanDefinitionReader
流操作实现载入,最后通过AbstractApplicationContext
的registerListeners
进行注册。这就是IoC容器的初始化过程。
其他容器的初始化过程,由上面的继承关系对比,就可以知道是差不多的,这里就不一个一个分析了。
更多推荐
所有评论(0)