源码学习 Spring 容器初始化流程
共计 15146 个字符,预计需要花费 38 分钟才能阅读完成。
0. 简介
本文以 ClassPathXmlApplicationContext
源码学习 Spring 初始化流程,那么首先要了解它实现了哪些接口,可以直观地了解到它具备了哪些能力。
/>
最重要的一点是它实现了 BeanFactory
接口,BeanFactory
其实就是常说的 ioc 容器,因为它实现了该接口,所以 ClassPathXmlApplicationContext
也是 ioc 容器。重点来了,ClassPathXmlApplicationContext
虽然实现了接口,但是它重写 BeanFactory
的方法都是委托给了成员变量 beanFactory
去实现。下面的代码都是其基类实现的。
// AbstractApplicationContext 实现
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
// AbstractRefreshableApplicationContext 实现
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " +
"call 'refresh' before accessing beans via the ApplicationContext");
}
return beanFactory;
}
ClassPathXmlApplicationContext
不但实现了 BeanFactory
接口,并且实现了其他的接口为容器扩展了功能如:消息国际化、资源解析器、事件发布、获取环境变量等功能。
构造函数时创建 ioc 容器的入口,代码如下:
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
执行构造方法,每个 ApplicationContext
都有自己的实现,但是都会初始化容器状态标识 active
、closed
。
ClassPathXmlApplicationContext
在执行构造方法时,并不会初始化beanFactory
。而AnnotationConfigApplicationContext
在初始化时并创建好beanFactory
,并将internalConfigurationAnnotationProcessor
、internalAutowiredAnnotationProcessor
等几个后 bean 后处理器注入,用于解析@Configuration
、@Autowired
等注解。如果全部以xml
的形式给容器注入 bean,那么是不需要这几个后处理器的,但是如果需要配置文件的方式也能使用注解,就需要配置<context:annotation-config/>
不管怎么说,都会执行 refresh()
方法用于刷新容器。其中 AbstractApplicationContext
的 refresh()
方法,代码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 执行刷新容器前的一些必要方法
prepareRefresh();
// 调用子类获取到 bean 工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置 bean 工厂,以增强功能
prepareBeanFactory(beanFactory);
try {
// 修改和调整 Bean 的定义(默认没有实现)
postProcessBeanFactory(beanFactory);
// 调用后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor,用于修改和增强 bean 的功能
registerBeanPostProcessors(beanFactory);
// 为上下文初始化 Message 源,即对不同语言的消息体进行国际化处理
initMessageSource();
// 初始化容器事件传播器
initApplicationEventMulticaster();
// 调用子类的某些特殊 Bean 初始化方法
onRefresh();
// 为事件传播器注册事件监听器(这里用到了观察者模式)
registerListeners();
// 初始化 Bean,并对 lazy-init 属性进行处理
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁创建的单态 Bean
destroyBeans();
// 取消 refresh 操作,重置容器的同步标识.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
1. prepareRefresh
protected void prepareRefresh() {
// 设置容器的启动时间,以便在刷新容器时进行时间跟踪
this.startupDate = System.currentTimeMillis();
// 容器在关闭时会设置该值为true,此时容器不能再进行一些初始化操作。
this.closed.set(false);
// 将容器的活动状态设置为true,表示容器当前处于活动状态。
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 初始化容器中可能使用的占位符属性源,例如 ${some.property},确保这些占位符被正确解析和设置。(这里的属性包含 JVM 属性 systemProperties,和操作系统的环境变量 systemEnvironment)
// 这是个空方法,是留给子类实现的。
initPropertySources();
// 验证所需要的属性都存在,否则抛出异常
getEnvironment().validateRequiredProperties();
// 设置监听器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
this.earlyApplicationEvents = new LinkedHashSet<>();
}
通过继承 ClassPathXmlApplicationContext
可以重写 initPropertySources()
方法,启动时校验必要参数。
public class MyInitApplicationContext extends ClassPathXmlApplicationContext {
public MyInitApplicationContext(String configLocation) throws BeansException {
super(configLocation);
}
@Override
protected void initPropertySources() {
super.initPropertySources();
System.out.println("test");
getEnvironment().setRequiredProperties("aaa");
}
}
2. obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 自己定义了抽象的 refreshBeanFactory() 方法,具体实现交给了自己的子类
refreshBeanFactory();
return getBeanFactory();
}
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
obtainFreshBeanFactory
方法用于创建 bean 工厂,调用 refreshBeanFactory
方法为一个抽象方法,需要子类自行实现。这里有一个好处,就是比如使用 xml
文件和注解方式,因为他们获取 bean 信息方式不同,可以通过自己重写该方法创建工厂。
refreshBeanFactory()
方法交由子类 AbstractRefreshableApplicationContext
实现:
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果已经建立了 IoC 容器,则销毁并关闭容器
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建 beanFactory 容器,DefaultListableBeanFactory 类实现了 ConfigurableListableBeanFactory 接口
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 添加一些自定义操作
customizeBeanFactory(beanFactory);
// 载入 BeanDefinition,在当前类中只定义了抽象的 loadBeanDefinitions() 方法,具体实现 调用子类容器
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
loadBeanDefinitions()
方法交由子类 AbstractXmlApplicationContext
实现:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建用于从 Xml 中读取 BeanDefinition 的读取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 配置 BeanDefinition 的读取器
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 为 beanDefinition 读取器设置 资源加载器,由于本类的基类 AbstractApplicationContext
// 继承了 DefaultResourceLoader,因此,本容器自身也是一个资源加载器
beanDefinitionReader.setResourceLoader(this);
// 设置 SAX 解析器,SAX(simple API for XML)是另一种 XML 解析方法。相比于 DOM,SAX 速度更快,占用内存更小。
// 它逐行扫描文档,一边扫描一边解析。相比于先将整个 XML 文件扫描进内存,再进行解析的 DOM,SAX 可以在解析文档的
// 任意时刻停止解析,但操作也比 DOM 复杂。
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化
initBeanDefinitionReader(beanDefinitionReader);
// Bean 读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
读取 BeanDefinition 的真正方法:
/**
* ClassPathXmlApplicationContext 与 FileSystemXmlApplicationContext 在这里的调用出现分歧,
* 各自按不同的方式加载解析 Resource 资源,最后在具体的解析和 BeanDefinition 定位上又会殊途同归。
*/
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
3. prepareBeanFactory
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器和属性、资源解析器
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 注册 AwareProcessor,用来给实现了 xxxAware 接口的类扩展功能
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 是忽略指定接口类型的属性的自动注入,而通过其他方式实现注入(通过上面的 ApplicationContextAwareProcessor 进行属性注入)
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 用于动态注册某些类型的依赖,使其可以被 Spring 容器自动注入
// 第一个参数为:希望注入的类型,第二个参数为当遇到这种希望注入的类型时,时间注入该对象
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 注册检测和解析实现 ApplicationListener 接口的后处理器
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 检测是否包含特定 bean,有则加入对应的后处理器
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册默认环境bean。environment、systemProperties、systemEnvironment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
对 BeanFactory 进行各种功能填充。其实如果自己直接 new 一个 BeanFactory,再添加上某些组件,也能够实现一个简单的容器。
这里主要是设置了一些类加载器和属性、资源解析器,还注册了一些后处理器用户处理实现特定接口的类,还注册了几个环境单例 bean。
4. postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
postProcessBeanFactory
方法主要用于在 Spring 容器实例化 bean 之前,修改和调整 bean 的定义。默认没有实现,子类可以重写。(ClassPathXmlApplicationContext
的基类 AbstractApplicationContext
对该方法并没有实现)
该方法与下面的 invokeBeanFactoryPostProcessors
方法效果一样,都是可以直接操作 beanFactory,可以新增、修改 bean 的定义。
5. invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
调用各种 BeanFactoryPostProcessor
,以实现对 bean 定义的新增和修改等,包括 spring 本身的和自己实现的 BeanFactoryPostProcessor
接口的类,通过委托 PostProcessorRegistrationDelegate
实现。
6. registerBeanPostProcessors
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
注册 BeanPostProcessor
,同样通过委托 PostProcessorRegistrationDelegate
实现。(注意这里是注册,而不是执行)
特性 | BeanFactoryPostProcessor |
BeanPostProcessor |
---|---|---|
执行时机 | 在 Bean 定义加载后、Bean 实例化之前。 | 在 Bean 实例化后、初始化方法之前或之后。 |
作用范围 | 主要用来修改或定制 Bean 定义(如修改属性、构造函数参数等)。 | 主要用来修改或增强 Bean 实例的行为。 |
执行对象 | 操作的是 BeanFactory 和 BeanDefinition ,改变 Bean 的元数据。 |
操作的是已经实例化的 Bean 对象。 |
修改内容 | 可以修改 Bean 的定义,如属性、依赖等。 | 可以修改实例化后的 Bean,增加自定义逻辑或增强功能。 |
常见用途 | 修改 Bean 配置、条件注册 Bean、动态改变 Bean 定义。 | 增强 Bean 功能、AOP、日志记录、延迟初始化等。 |
7. initMessageSource
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
8. initApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
事件广播器负责在应用程序中传递事件,确保事件可以从发布者传播到所有的监听者。这个方法的功能是确保容器中有一个有效的 ApplicationEventMulticaster
,并根据容器中是否已经存在相应的 bean 来进行初始化。
9. onRefresh
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}
空方法,用于留给子类进行扩展。
10. registerListeners
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
所有注册的 bean 中查找监听器,注册到应用事件广播器中。
11. finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 如果有的话,初始化默认转换服务。
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 注册嵌入式值解析器,以支持占位符(placeholders)解析的功能。例如:${property.name}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 初始化 LoadTimeWeaverAware 实例
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时类加载器,并将其清除。
beanFactory.setTempClassLoader(null);
// 锁定 beanFactory 配置。一旦进入这个阶段,Spring 假设所有的 Bean 定义已经准备就绪,锁定配置,以提升性能。
// 1. 不再允许新增或修改 Bean 定义 2. 可以更高效地缓存元数据,例如 Bean 的依赖关系或类型信息。
beanFactory.freezeConfiguration();
// 实例化所有非延迟加载的 bean
beanFactory.preInstantiateSingletons();
}
初始化剩下的非懒加载实例,程序员自己编写的大部分 bean 都是在这里进行初始化的。在这里调用了 getBean
方法,创建了非惰性的 bean 实例。getBean
方法其中会调用 createBean
方法,毕竟 getBean
所需要获取的 bean
这里具体就涉及到了 bean 的生命周期,比较复杂,可以当作另外一个探究的点。
12. finishRefresh
protected void finishRefresh() {
// 清楚资源缓存
clearResourceCaches();
// 初始化生命周期处理器
initLifecycleProcessor();
// 触发生命周期处理器的刷新事件
getLifecycleProcessor().onRefresh();
// 发布上下文刷新事件
publishEvent(new ContextRefreshedEvent(this));
// 注册到 LiveBeansView
// LiveBeansView 是 Spring 提供的工具类,用于调试和监控应用中定义的 bean。
LiveBeansView.registerApplicationContext(this);
}
Tips:清朝云网络工作室