springboot(2.4.1)源代码分析五refreshContext
上一篇记录了springboot的应用上下文的初始化、准备以及加载,本篇接着记录run 方法中最核心的方法,refreshContext,刷新上下文,这里有初始化bean工厂,单例对象实例化等等逻辑,算是spring启动过程中关键一步,涉及的方法和逻辑也很多,下面还是先看run方法。
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context); //这么一个重要的方法,取名叫刷新上下文,容易让人忽视,实际上这个方法很关键
afterRefresh(context, applicationArguments);
......
return context;
}
refreshContext方法中最核心的逻辑就在org.springframework.context.support.AbstractApplicationContext.refresh()这个方法中:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//准备刷新工作
prepareRefresh();
//获取 BeanFactory 实例。其中包含 读取 bean 配置,创建bean 实例对象相关代码逻辑。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//对获取的 BeanFactory 实例对象进行预处理
prepareBeanFactory(beanFactory);
try {
//子类重写此方法进行定制化处理.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 回调 BeanFactoryPostProcessors 实现类的postProcessBeanFactory方法,进行BeanFactory后置处理。
invokeBeanFactoryPostProcessors(beanFactory);
// 向 BeanFactory 中注册 BeanPostProcessor 实现类
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//设置 context 消息的国际化实现类。如果没有配置,则使用 DelegatingMessageSource 实现。
initMessageSource();
//设置 context 广播器(applicationEventMulticaster)。如果没有配置,则使用 SimpleApplicationEventMulticaster 实现。
initApplicationEventMulticaster();
// 根据需要,子类自定义 onRefresh()
onRefresh();
// 注册 Listeners (列表),广播 earlyApplicationEvents 事件.
registerListeners();
// BeanFactory 最终的初始化操作.
finishBeanFactoryInitialization(beanFactory);
// 上下文(context) 后续处理逻辑.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// 清理公共缓存。
resetCommonCaches();
contextRefresh.end();
}
}
}
重点方法说明:
- prepareRefresh
刷新方法之前预处理上下文信息:
- 记录服务启动是时间戳
- 设置当前服务 context 关闭标记(closed),活动标记(active)
- 根据需要执行特殊的属性初始化操作。
- 校验必须配置属性是否设置成功
- 设置早期的事件监听列表 ApplicationListener 列表。
- prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)
对获取的 BeanFactory 实例对象进行预处理。
- 设置 Bean 的类加载器(beanClassLoader)。
- 根据配置 spring.spel.ignore 添加表达式解析工具类实例(StandardBeanExpressionResolver)。
- 添加属性编辑器注册器(ResourceEditorRegistrar)。
- 添加 Aware 接口执行器(ApplicationContextAwareProcessor),并将 Aware的子接口 接口设置为忽略依赖接口。
- 注册 指定类型类的实例。BeanFactory.class, beanFactory
- 添加实现BeanPostProcessor接口的 Listener 装饰器 (ApplicationListenerDetector)。后续将实现 ApplicationListener 的bena添加到 applicationListeners 列表钟。
- 如果配置了loadTimeWeaver实现,则添加实现BeanPostProcessor接口的 LoadTimeWeaverAwareProcessor。后续给实现LoadTimeWeaverAware 的bean设置LoadTimeWeaver实现对象。实际中使用较少。
类加载期织入(LTW) : 在类加载器加载时,通过字节码编辑技术将切面织入目标类字节码上 。(https://www.jianshu.com/p/25cd25046fab) 类加载期织入有两种方式:一种是在 main 方法执行之前,通过 premain 来实现;另一种是在程序运行中,通过 attach api 来实现。 运行期织入:在创建类对象实例时,使用CGLib代理或JDK动态代理进行切面的织入。
- 将环境变量和系统属性相关的对象实例注册到 单例Bean Map中。
getEnvironment().getSystemProperties() JVM 启动时相关的环境属性信息
getEnvironment().getSystemEnvironment() OS 系统的环境变量相关属性信
- invokeBeanFactoryPostProcessors(beanFactory)
回调 BeanFactoryPostProcessors 实现类的postProcessBeanFactory方法,进行BeanFactory后置处理。
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
- 根据 PriorityOrdered,Ordered以及常规的 BeanDefinitionRegistryPostProcessor 实现类 顺序依次调用 的 postProcessBeanDefinitionRegistry 方法。
- 根据 PriorityOrdered,Ordered以及常规的 BeanFactoryPostProcessors 实现类 顺序依次调用 的postProcessBeanFactory方法。
- registerBeanPostProcessors(beanFactory)
向 BeanFactory 中注册 BeanPostProcessor 实现类。
PostProcessorRegistrationDelegate.registerBeanPostProcessors
1.从 BeanFactory 取出 beanDefinitionMap 中所有 BeanPostProcessor 实现类
2. 按 PriorityOrdered,Ordered以及nonOrdered 顺序添加到 BeanFactory的beanPostProcessors 列表中。
如果 一个实现类继承 MergedBeanDefinitionPostProcessor 接口时,则添加到列表最后。
-
registerListeners()
注册 Listeners (列表),广播 earlyApplicationEvents 事件。
1.将 context 的 applicationListeners (列表) 添加到广播器(applicationEventMulticaster)的applicationListeners(列表)中。
2.将 BeanFactory 中管理的所有 ApplicationListener 类型Bean添加到广播器(applicationEventMulticaster) applicationListenerBeans(列表)中。
3.将 earlyApplicationEvents 事件列表发送到广播器(applicationEventMulticaster)。将遍历触发满足监听事件的 ApplicationListener.onApplicationEvent 方法。 -
finishBeanFactoryInitialization(beanFactory)
BeanFactory 最终的初始化操作
- beanFactory 设置 ConversionService 实现Bean。
- beanFactory 设置 EmbeddedValueResolver 实现Bean。
- 获取 beanFactory 所有 LoadTimeWeaverAware 类型 bean。并创建 bean 实例。
- beanFactory 设置 tempClassLoader 为 null。阻止再使用 tempClassLoader
- beanFactory 冻结配置 beanDefinitionNames。为后面 批量处理单例 Bean 做准备。
- beanFactory 获取所有非懒加载的单例 bean对象。
-
finishRefresh()
上下文(context) 后续处理逻辑。
- 清理资源缓存(resourceCaches)信息
- 设置 context 的生命周期处理器 (LifecycleProcessor)。如果没有配置,则使用 DefaultLifecycleProcessor 实现。
- 调用 LifecycleProcessor.onRefresh 方法。获取 beanFactory 中所有 Lifecycle 类型bean,按 Phased 分组进行排序,然后遍历执行 Lifecycle.start 方法。
- 发布 ContextRefreshedEvent 事件。先向当前上下文(context) 环境发送事件广播。然后向父类发布 ContextRefreshedEvent 事件广播。
- 获取 平台 MBeanServer 实现,将 LiveBeansView 和 applicationName 注册到 MBeanServer 中。
- resetCommonCaches()
清理公共缓存。
1.清理反射中缓存的方法和字段信息。
2.清理注解缓存的信息。
3.清理解析类型相关的缓存信息。
4.清理类加载器相关的信息。
参考:https://www.cnblogs.com/StreamPlume/p/15668476.html
标题:springboot(2.4.1)源代码分析五refreshContext
作者:michael
地址:https://blog.junxworks.cn/articles/2022/12/14/1671010010551.html