Spring源码分析之ApplicationContext
2022/5/12 20:27:39
本文主要是介绍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对国际化的支持 。
参考
Spring IOC 容器源码分析
这篇关于Spring源码分析之ApplicationContext的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南