第4节 Spring容器启动源码概览
一、 什么是 Spring
容器
我们通常所说的Spring
容器就是 IOC
容器,主要用于对所有Bean
对象的管理。Spring
中的 org.springframework.beans.factory.BeanFactory
就是容器的根接口。
对于
BeanFactory
类图,应该熟记几个关键的类,比如DefaultListableBeanFactory
、ConfigurableBeanFactory
、ConfigurableListableBeanFactory
、DefaultSingletonBeanRegistry
等。
/**
* The root interface for accessing a Spring bean container.
* 访问Spring容器的根接口
*
* Bean factory implementations should support the standard bean lifecycle interfaces
* as far as possible. The full set of initialization methods and their standard order is:
* (一)容器启动时:BeanFactory 的实现尽可能的支持Bean的生命周期,整个Bean加载的应该遵循如下方法调用顺序:
* 1. 如果bean实现了Aware相关接口,则调用Aware接口方法。常见的Aware接口:
* (1)BeanNameAware
* (2)BeanClassLoaderAware
* (3)BeanFactoryAware
* (4)EnvironmentAware
* (5)EmbeddedValueResolverAware
* (6)ResourceLoaderAware
* (7)ApplicationEventPublisherAware
* (8)MessageSourceAware
* (9)ApplicationContextAware
*
* 2. 调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
* 3. 调用 InitializingBean 的 afterPropertiesSet 方法
* 4. 调用 init-method 标记的方法
* 5. 调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
*
* On shutdown of a bean factory, the following lifecycle methods apply:
* (二)容器关闭时,应该依次调用如下生命周期方法
* 1. 调用 DestructionAwareBeanPostProcessor 的 postProcessBeforeDestruction 方法
* 2. 调用 DisposableBean 的 destroy 方法
* 3. 调用 destroy-method 标记的方法
*/
public interface BeanFactory {
}
BeanFactory
接口注释中明确了IOC
容器中的Bean
的生命周期流程,后续笔记中会详细说明生命周期的细节问题。
对于开发人员来讲,我们见到最多应该是org.springframework.context.ApplicationContext
接口,而不是BeanFactory
,其实ApplicationContext
就是BeanFactory
的子接口,可以理解为它是BeanFactory
的功能扩展,是一个支持更多功能的IOC
容器。我们经常使用的是 ApplicationContext
接口的实现类 ClassPathXmlApplicationContext
。
二、 Spring
容器如何启动
知道了Spring
容器就是 ApplicationContext
对象,那么容器启动流程其实就是 ApplicationContext
对象创建、初始化、使用、销毁的过程。
1. 整个IOC容器启动概览
首先我们来看这样一段代码,如下图所示:
Spring
是如何完成xml
文件到我们代码中bean
对象的转换的呢?我想大概流程应该如下:
BeanDefinition
是什么? 它是Spring
框架的一个接口,定义了Java bean
对象的一些信息,比如属性、构造参数等信息。
/**
* A BeanDefinition describes a bean instance, which has property values,
* constructor argument values, and further information supplied by
* concrete implementations.
*/
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// ...
}
- 容器是如何来存放这些
bean
对象信息的? 在实际开发中,我们经常会做一些本地缓存,通常使用Map
。那么Spring
框架也是用了Map
来作为存储bean
对象信息的数据结构。它定义在BeanFactory
的实现类DefaultListableBeanFactory
中,如下:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
}
- 初始化好的
bean
实例又放在哪里? 大家都知道Spring
中的bean
是单例模式,只会加载一次。当xml
文件中配置User
对象在实例化好后,它在容器中如何存放的。该问题就涉及到Spring
的一级缓存,定义在DefaultSingletonBeanRegistry
中。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name --> bean instance
* Spring 中的一级缓存
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory
* Spring 中的三级缓存,用于保存 beanName 和 创建bean的工厂直接的关系
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance
* Spring 中的二级缓存,与一级缓存不同之处,当一个单例的bean放到这里之后,那么当bean还在创建过程中就可以通过getBean方法获取,可以方便的进行循环依赖检测
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
}
1.1 简单版流程图
BeanFactoryPostProcessor 和 BeanPostProcessor 的区别
-
BeanFactoryPostProcessor
:可以在Bean实例化之前,对Bean的定义信息(BeanDefinition:配置元数据)进行修改。如果你配置了多个BeanFactoryPostProcessor
,可通过实现Ordered
接口来控制它的执行顺序 -
BeanPostProcessor
:它是在Bean完成实例化和Bean属性填充之后执行,主要是对Bean的属性做一系列的修改
2. IOC容器启动源码入口
(1) 方法入口
@Test
public void testUser() {
// 创建Spring容器
ApplicationContext cx = new ClassPathXmlApplicationContext("application-bean.xml");
User user = cx.getBean("user", User.class);
System.out.printf(user.getUsername());
}
(2)ClassPathXmlApplicationContext
构造器
/**
* 创建 ClassPathXmlApplicationContext 对象
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, null);
}
/**
* 创建Spring容器上下文
* @param configLocations xml资源文件路径
* @param refresh 是否刷新容器
* @param parent 父类容器
* @throws BeansException 容器创建失败异常
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh,
@Nullable ApplicationContext parent) throws BeansException {
super(parent);
// 设置资源文件路径,比如 xml 配置文件
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
(3)容器启动的核心方法:refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/** Prepare this context for refreshing.
* 1.容器刷新前的准备工作
* (1) 设置容器的启动时间
* (2) 设置活跃状态为true
* (3) 设置关闭状态为false
* (4) 获取 Environment 对象,并加载当前系统属性值到 Environment 对象中
* (5) 准备监听器和事件的集合对象,默认空集合
*/
prepareRefresh();
/** Tell the subclass to refresh the internal bean factory.
* (1) 创一个新的 BeanFactory 对象,即 DefaultListableBeanFactory 对象
* (2) 该步骤中有一个很重要的逻辑就是通过 loadBeanDefinitions() 方法将所有的 BeanDefinition 对象刷新到 DefaultListableBeanFactory 中 beanDefinitionMap 属性中
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/** Prepare the bean factory for use in this context.
* 给容器对象 BeanFactory 的属性值赋值操作,通过一系列的add、set、ignore和register开头的方法完成赋值操作
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses. 是一个模板方法
postProcessBeanFactory(beanFactory);
/** Invoke factory processors registered as beans in the context.
* 注册 BeanFactoryPostProcessor 处理器,并调用 BeanFactoryPostProcessor 处理器的实现,可以用于扩展对 Bean 的 BeanDefinition 信息修改
*/
invokeBeanFactoryPostProcessors(beanFactory);
/** Register bean processors that intercept bean creation.
* (1) 将Spring自带的或者用户自定义的 BeanPostProcessor 处理器到 DefaultListableBeanFactory 的 beanPostProcessors 集合属性中
* (2) 可以用于扩展对实例化后的 Bean 对象属性进行修改
*/
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化 MessageSource,用于支持国际化处理
initMessageSource();
/** Initialize event multicaster for this context.
* (1) 初始化事件广播器 ApplicationEventMulticaster
* (2) 作用:将所有 ApplicationEventPublisher 发布的 ApplicationEvent 事件都广播给对应的事件侦听器
*/
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 模板方法
onRefresh();
// Check for listener beans and register them.
// 注册事件监听器 ApplicationListener
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 完成 Spring 容器中非懒加载的单例 bean 对象的实例化。Spring Bean 初始化的核心方法。
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成上下文刷新,即 ApplicationContext 的刷新工作完成
finishRefresh();
} catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
// 清空容器中的单例 bean
destroyBeans();
// Reset 'active' flag.
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();
}
}
}
二、 总结
- 本篇笔记只是简单的对
Spring
容器启动做了初步整理,后续会对其中的细节进行深入整理 - 对
Spring
源码中常见的接口有个初步印象,比如:BeanFactory
Aware
BeanDefinition
BeanDefinitionReader
BeanFactoryPostProcessor
BeanPostProcessor
Environment
StandardEnvironment
FactoryBean
转载自:https://juejin.cn/post/7242876385735180345