作为Spring IOC容器的核心,ApplicationContenxt提供了很多功能接口,这篇文章主要从源码介绍ApplicationContext的初始化过程中做了些什么事情。
其他一些以Spring为基础的框架也大量使用了ApplicationContext的功能,比如Mybatis、Dubbo等,阅读完成,相信你会更容易理解这些框架的工作原理,自己也会写一些通用的框架组件。
入口
ApplicationContext有很多不同的实现,通常继承了AbstractApplicaitonContext:
- 或最原始的通过容器web.xml的ContextLoaderListener、通过xml创建ClassPathApplicationContext
- 或通过Spring Boot创建 AnnotationConfigServletWebServerApplicationContext
初始化入口,基本都有下面两个过程:
-
设置配置元数据类型和路径(xml位置、配置注解类)
// 设置配置路径,设置配置类等等 setConfigLocations(configLocations); register(annotatedClasses); -
refresh,进行容器创建、初始化,设置一些功能的处理器等;后面详细介绍
// 核心方法 refresh();
AbstractApplicaitonContext的refresh方法
BeanFactory创建准备
一些系统属性、环境变量获取,校验
// AbstractApplicaitonContext.refresh
prepareRefresh();
// AbstractApplicaitonContext.prepareRefresh
// 用于环境变量替换placeholder功能
initPropertySources();
getEnvironment().validateRequiredProperties();
BeanFactory对象创建
- 创建DefaultListableBeanFactory,作为beanFactory属性放在ApplicationContext中;
(加载bean定义,由具体子类实现(xml/注解))
// AbstractApplicaitonContext.refresh
// 获取BeanFactory,beanFactory作为一个属性被子类持有,两种实现(一个beanFactory只创建一次,一个每次刷新创建)
// 以前会使用,可刷新的实现:AbstractRefreshableApplicationContext,用在外部容器内部,猜想可能是因为外部容器bean生命周期不能由Spring控制,所以每次刷新重新创建一遍
// 但是最新常用的,spring-boot使用的已经是另一个:GenericWebApplicationContext,自己创建容器Server,beanFactory每次刷新只有一个,刷新由SpringBoot启动类控制
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// AbstractApplicaitonContext.obtainFreshBeanFactory
refreshBeanFactory(); // 由两个子类实现
// AbstractRefreshableApplicationContext.refreshBeanFactory
// 加载bean定义,由子类实现,可能为xml形式,可能为注解形式
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
// GenericWebApplicationContext.refreshBeanFactory 啥也不做,因为只有一个beanFactory,后面会使用别的方式加载beanDefinition,比如BeanFactoryPostProcessor
TODO Spring boot等新型的GenericWebApplicationContext实现如何扫描BeanDefinition的呢?留在BeanDefinition的加载文章中说
BeanFactory功能扩展
准备beanFactory,添加一些特殊bean
添加用于实现一些功能的BeanPostProcessor等,比如:
- Spring特殊bean接口相关的回调功能:如ContextAware接口功能、ApplicationListener接口监听事件功能等
// AbstractApplicaitonContext.refresh
prepareBeanFactory(beanFactory);
// AbstractApplicaitonContext.prepareBeanFactory
// SpEl表达式的支持 #{}
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 属性注册编辑器,用于xml设置bean属性时,可以从文本转换为对应需要的类型
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加特殊的BeanPostProcessor,处理一些Aware方法,在后面bean初始化生命周期时机调用,与ApplicationContext有关,区别bean加载调用的beanName,beanFactory等,不同。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 上面忽略的,对应有直接可注入类型的依赖,其它还有一些
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 处理实现ApplicationListener接口的bean,实现事件发布与订阅,bean初始化生命周期中调用添加/移除listener
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
主要是一些Web的ApplicaitonContext继承使用,添加一些容器相关的如Servlet~Aware接口的bean初始化前调用
BeanFactoryPostProcessor调用
与BeanPostProcessor作用于Bean不同,BeanFactoryPostProcessor作用于BeanDefinition
refresh方法接下来会调用BeanFactoryPostProcessor,传入beanFactory获取到配置元数据,实例化之前可以修改bean定义
典型应用:PropertyPlaceHolderConfigurer,可以使用~ValueResolver结合BeanDefinitionVisitor对BeanDefinition进行修改。
问题:BeanFactoryPostProcessor,其实也是一类特殊的bean,在这一步就被创建完成,调用它的后置处理方法。
// AbstractApplicaitonContext.refresh
// 子类去覆盖实现
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor beanFactory的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// AbstractApplicaitonContext.invokeBeanFactoryPostProcessors
// 调用 BeanFactoryPostProcessors,用来修改BeanDefinition,实现比如使用 properties、enviroment
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
// 这里会获取到所有 BeanFactoryPostProcessor类型的bean
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 直接这时就创建这些bean
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
// 调用这些bean的后置处理方法
postProcessor.postProcessBeanDefinitionRegistry(registry);
BeanPostProcessor的注册
refresh方法的下一步是注册BeanPostProcessor,内部获取并加载BeanPostProcessor类型bean,注册到beanFactory中,真正的调用在bean加载时,实例化之后,属性设置完成,初始化前后。
// AbstractApplicaitonContext.refresh
registerBeanPostProcessors(beanFactory);
// AbstractApplicaitonContext.registerBeanPostProcessors方法
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
// PostProcessorRegistrationDelegate.registerBeanPostProcessors方法,类似前面BeanFactoryPostProcessor的操作
// 从BeanDefinition中获取 BeanPostProcessor类型的bean名称
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 直接这时就创建这些bean
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// 将bean 添加到beanFactory中,后面bean加载时调用,多次add只会改变顺序,不会添加多个
beanFactory.addBeanPostProcessor(postProcessor);
消息及国际化
消息源Bean MessageSource的加载,注册,作用是通过code获取String类型的message,可以根据不同Locale匹配实现国际化
如果用户自定义了,直接加载,如果没有定义,创建默认的,直接注册为单例,不用beanFactory加载。
initMessageSource();
事件发布
加载注册应用消息广播器ApplicationEventMulticaster bean,默认SimpleApplicationEventMulticaster,实现了两个主要接口,分别用来:
- 维护listener,add、remove注册事件的监听器
- 传播事件,提供multicastEvent方法(默认同步,可以自定义线程池,异步处理消息逻辑)
// AbstractApplicaitonContext.refresh
initApplicationEventMulticaster();
// 如果没自定义,直接使用SimpleApplicationEventMulticaster,可以配置执行器线程池异步发送消息
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
这里使用了观察者设计模式,发布订阅模式一般具有订阅调度中心,即事件广播者Bean,被组合到ApplicationContext中专门用来完成事件传播功能
// AbstractApplicaitonContext.refresh
// 子类实现,比如Spring Boot的SpringApplication就是用这个onRefresh回调来进行Server容器的创建
onRefresh();
注册ApplicationListener类型bean到事件广播器的一个set中
// AbstractApplicaitonContext.refresh
// 获取所有ApplicationListener类型的bean,注册到ApplicationEventMulticaster的set域中
registerListeners();
Event泛型参数的获取
Spring中要监听某个事件,写一个实现接口ApplicationListener的bean就可以了
public class AnsiOutputApplicationListener
implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
}
是通过ResolvableType工具类,可以方便的获取某个对象的类所实现的接口的泛型参数
加载非懒单例bean
加载所有非懒加载的bean,包括一些Spring实现功能自带的Bean,和用户定义的非懒加载Bean:
// AbstractApplicaitonContext.refresh
finishBeanFactoryInitialization(beanFactory);
// AbstractApplicaitonContext.finishBeanFactoryInitialization
// 加载converters和formatters
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
// 加载所有用户定义的非懒加载bean
beanFactory.preInstantiateSingletons();
// DefaultListableBeanFactory.preInstantiateSingletons
getBean(beanName);
加载Bean的过程比较复杂,会单独列出一篇文章。
refresh完成后工作
完成刷新,清除缓存,回调LifecycleProcessor事件方法,ContextRefreshedEvent,加入到LiveBeansView中
// AbstractApplicaitonContext.refresh
finishRefresh();
// AbstractApplicaitonContext.finishRefresh
// 初始化实现Spring生命周期的Bean
initLifecycleProcessor();
// 回调
getLifecycleProcessor().onRefresh();
// 发布事件
publishEvent(new ContextRefreshedEvent(this));
总结
ApplicationContext在实现BeanFactory接口相关的功能时,增加了许多功能,在加载完成BeanDefinition(这里没有涉及)之后,核心的refresh方法主要实现了以下功能:
- 环境变量、系统属性支持
- spEl表达式支持、PropertyEditor等文本属性转换支持
- 添加BeanPostProcessor,用作实现特殊接口Bean的包括各种生命周期方法回调实现
- BeanFactoryPostProcessor后置处理,修改BeanDefinition,
- 向容器中添加包括用户定义的BeanPostProcessors
- 消息和国际化
- 事件发布广播中心Bean创建
- 提供生命周期回调功能
- 加载Bean