一、spring加载流程
tomcat在启动ServletContext容器的时候会发布ServletContextEvent事件,Spring就通过实现ServletContextListener接口,监听该事件来监听ServletContext的生命周期。web.xml中配置了ContextLoaderListener实现了ServletContextListener接口。对ServletContext启动监听,在initWebApplicationContext方法中会通过ServletContext获取web.xml中配置的contextConfigLocation参数值,也就是spring的xml配置
refresh 是 AbstractApplicationContext 中的一个方法,负责初始化 ApplicationContext 容器,容器必须调用 refresh 才能正常工作。它的内部主要会调用 12 个方法,我们把它们称为 refresh 的 12 个步骤:
prepareRefresh:
一开始设置启动时间及开启启动标识
Environment 对象的作用之一是为后续 @Value,值注入时提供键值
保存 java 环境键值、保存系统环境键值、保存自定义键值
obtainFreshBeanFactory
这一步获取(或创建)BeanFactory,BeanFactory 的作用是负责 bean 的创建、依赖注入和初始化,bean 的各项特征由 BeanDefinition 定义
BeanDefinition 作为 bean 的设计蓝图,规定了 bean 的特征,如单例多例、依赖关系、初始销毁方法等
所有的 BeanDefinition 会存入 BeanFactory 中的 beanDefinitionMap 集合
BeanDefinition 的来源有多种多样,可以是通过 xml 获得、配置类获得、组件扫描获得,也可以是编程添加
prepareBeanFactory
这一步会进一步完善 BeanFactory,为它的各项成员变量赋值,并应用 ApplicationContext 提供的 Environment 完成 ${ } 解析
postProcessBeanFactory
这一步是空实现,留给子类扩展。
一般 Web 环境的 ApplicationContext 都要利用它注册新的 Scope,完善 Web 下的 BeanFactory
这里体现的是模板方法设计模式
invokeBeanFactoryPostProcessors
这一步会调用 beanFactory 后处理器
beanFactory 后处理器,充当 beanFactory 的扩展点,可以用来补充或修改 BeanDefinition
常见的 beanFactory 后处理器有:ConfigurationClassPostProcessor – 解析 @Configuration、@Bean、@Import、@PropertySource 等;PropertySourcesPlaceHolderConfigurer – 替换 BeanDefinition 中的 ${ };MapperScannerConfigurer – 补充 Mapper 接口对应的 BeanDefinition。
registerBeanPostProcessors
这一步是继续从 beanFactory 中找出 bean 后处理器,添加至 beanPostProcessors 集合中
bean 后处理器,充当 bean 的扩展点,可以工作在 bean 的实例化、依赖注入、初始化阶段,常见的有:AutowiredAnnotationBeanPostProcessor 功能有:解析 @Autowired,@Value 注解;CommonAnnotationBeanPostProcessor 功能有:解析 @Resource,@PostConstruct,@PreDestroy;AnnotationAwareAspectJAutoProxyCreator 功能有:为符合切点的目标 bean 自动创建代理。
initMessageSource
这一步是为 ApplicationContext 添加 messageSource 成员,实现国际化功能
去 beanFactory 内找名为 messageSource 的 bean,如果没有,则提供空的 MessageSource 实现
initApplicationEventMulticaster
这一步为 ApplicationContext 添加事件广播器成员,即 applicationContextEventMulticaster,它的作用是发布事件给监听器
去 beanFactory 找名为 applicationEventMulticaster 的 bean 作为事件广播器,若没有,会创建默认的事件广播器
onRefresh
这一步是空实现,留给子类扩展
SpringBoot 中的子类在这里准备了 WebServer,即内嵌 web 容器
体现的是模板方法设计模式
registerListeners
这一步会从多种途径找到事件监听器,并添加至 applicationEventMulticaster用来接收事件广播器发布的事件
有如下来源:事先编程添加的;来自容器中的 bean;来自于 @EventListener 的解析;要实现事件监听器,只需要实现 ApplicationListener 接口,重写其中 onApplicationEvent(E e) 方法即可;
finishBeanFactoryInitialization
这一步会将 beanFactory 的成员补充完毕,并初始化所有非延迟单例 bean
singletonObjects 即单例池,缓存所有单例对象
对象的创建都分三个阶段,每一阶段都有不同的 bean 后处理器参与进来,扩展功能
finishRefresh
这一步会为 ApplicationContext 添加 lifecycleProcessor 成员,用来控制容器内需要生命周期管理的 bean
如果容器中有名称为 lifecycleProcessor 的 bean 就用它,否则创建默认的生命周期管理器
准备好生命周期管理器,就可以实现
调用 context 的 start,即可触发所有实现 LifeCycle 接口 bean 的 start。调用 context 的 stop,即可触发所有实现 LifeCycle 接口 bean 的 stop。
发布 ContextRefreshed 事件,整个 refresh 执行完成
其中:
1 为准备环境
2 3 4 5 6 为准备 BeanFactory
7 8 9 10 12 为准备 ApplicationContext
11 为初始化 BeanFactory 中非延迟单例 bean
Exception(异常情况)
原文链接:https://blog.youkuaiyun.com/qq_40322236/article/details/127390957
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}