Spring源码分析之ApplicationContext
前言
通过前面的博客我们已经对Spring的IOC容器有了一定的了解,它的底层实现为DefaultListableBeanFactory,这是一个BeanFactory,
ApplicationContext在BeanFactory容器的基础上又增加了很多功能,如事件分发,国际化等。相关类图如下
可以看到ApplicationContext是BeanFactory的子接口,但是它没有自己实现这些方法,对于Bean的操作,都是委托给BeanFactory来处理的。
ApplicationContext有很多实现类,如支持XML配置的ClassPathXmlApplicationContext,支持注解配置的AnnotationConfigApplicationContext,
支持内嵌Tomcat和注解的AnnotationConfigServletWebServerApplicationContext(SpringBoot默认使用)。
这里我们以ClassPathXmlApplicationContext为例来分析,AnnotationConfigApplicationContext对于注解的处理额外做了很多工作,不利于分析流程。
简单使用
首先在classpath下创建一个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="userService"
class="com.imooc.sourcecode.java.spring.ioc.test4.TestXmlContext.UserService"/>
</beans>
使用ClassPathXmlApplicationContext来解析此配置文件
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestXmlContext {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
context.setConfigLocation("spring.xml");
context.refresh();
UserService userService = (UserService) context.getBean("userService");
userService.userList();//userList
}
public static class UserService {
public void userList() {
System.out.println("userList");
}
}
}
使用方式很简单,但Spring内部帮我们做了很多工作。
源码分析
核心为refresh()方法,进入父类AbstractApplicationContext中
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//做一些准备工作,主要是environment对象的创建
prepareRefresh();
//创建DefaultListableBeanFactory容器,并从XML配置文件中加载BeanDefinition,注册到容器中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//配置BeanFactory,设置ClassLoader,设置SpringEL表达式解析器,向BeanFactory中添加特定的BeanPostProcessor
prepareBeanFactory(beanFactory);
try {
//对beanFactory做一些处理,留给子类扩展
postProcessBeanFactory(beanFactory);
//从容器中获取所有类型为BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的Bean,并执行他们的扩展方法
//这两个类是Spring提供的两种扩展
//ConfigurationClassPostProcessor(用来解析@Configuration类,注解自动扫描等)就是在这一步执行的
invokeBeanFactoryPostProcessors(beanFactory);
//从容器中获取所有类型为BeanPostProcessor的Bean,并设置到BeanFactory中(调用BeanFactory的addBeanPostProcessor()方法)
//最重要的AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)就是在这添加的
registerBeanPostProcessors(beanFactory);
//初始化MessageSource,这是一个支持国际化的组件
initMessageSource();
//初始化事件分发器,默认类型为SimpleApplicationEventMulticaster,通过它我们可以实现事件的订阅和发布
initApplicationEventMulticaster();
//留给子类扩展,ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步创建了WebServer(默认是Tomcat),注意,还没启动
onRefresh();
//从容器中获取所有类型为ApplicationListener的Bean,并注册到事件分发器中
//SpringBoot会从spring.factories中获取配置的ApplicationListener列表,
//如ConfigFileApplicationListener(用来解析application.yml文件或application.properties文件)
registerListeners();
//实例化所有非懒加载的单例Bean,其实就是依次调用getBean(name)方法,BeanFactory会在第一次调用时创建Bean
finishBeanFactoryInitialization(beanFactory);
//实例化DefaultLifecycleProcessor对象(这是一个生命周期处理器),
//发布ContextRefreshedEvent事件(监听此事件的ApplicationListener都会处理)
//ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步启动WebServer(默认是Tomcat)
finishRefresh();
}
catch (BeansException ex) {
//如果抛出异常,销毁所有已经创建的Bean
destroyBeans();
//重置active标识
cancelRefresh(ex);
throw ex;
}
finally {
//清空缓存,如反射的缓存
resetCommonCaches();
}
}
}
此方法执行完,我们的ApplicationContext对象可以算是初始化完成了,所有的非懒加载Bean也已经创建完成了。
上面的每一个方法实现都是比较复杂的,细节很多,这里我们再简单分析一下obtainFreshBeanFactory()方法。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//创建并初始化BeanFactory
refreshBeanFactory();
return getBeanFactory();
}
继续跟进去refreshBeanFactory()方法,AbstractRefreshableApplicationContext类重写了此方法
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果已经创建过BeanFactory,销毁所有Bean
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建一个新的beanFactory,可以看到实现为DefaultListableBeanFactory类型
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
//从XML配置文件中加载BeanDefinition
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
}
分析总结
从上面的类图可以看到,ApplicationContext接口继承ApplicationEventPublisher(事件分发器),MessageSource(国际化相关),BeanFactory(IOC容器),
但ApplicationContext的实现类本身没有实现这些接口的方法,而是委托给对应的实现类,如事件分发委托给SimpleApplicationEventMulticaster,
国际化委托给ResourceBundleMessageSource(我们需要自己定义此Bean),IOC容器委托给DefaultListableBeanFactory。
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
以getBean()方法为例,可以看到确实是交给内部的BeanFactory来处理的。
关于国际化,可以查看Spring对国际化的支持 。