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對國際化的支援 。