Spring Boot启动流程
基础准备
1,BeanPostProcessor:这个接口的作用在于对于新构造的实例可以做一些自定义的修改。比如如何构造、属性值的修改、构造器的选择等等
2,BeanFactoryPostProcessor:在容器实例化任何其它bean之前读取配置元数据,并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉
3,BeanDefinitionRegistryPostProcessor:允许在普通的BeanFactoryPostProcessor接口实现类执行之前注册更多的BeanDefinition。特别地是,BeanDefinitionRegistryPostProcessor可以注册BeanFactoryPostProcessor的BeanDefinition
4,Import:通过注解导入BeanDefinition,例如EnableAutoConfiguration导入spring.factories配置的各种配置类。在ImportSelector中选择要导入的Configuration类或者通过ImportBeanDefinitionRegistrar添加BeanDefinition,基于注解的导入可以通过配置属性值决定导入那些类
应用初始化
@Configuration
@EnableAutoConfiguration//三个注解的使用后面ConfigurationClassPostProcessor部分会讲到
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
构造SpringApplication对象
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
// 为成员变量sources赋值
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
//从spring.factories加载ApplicationContextInitializer,用来初始化ApplicationContext,在prepareContext中调用,例如DuibaEnvironmentDecryptApplicationInitializer对配置进行解密
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从spring.factories加载ApplicationListener,订阅ApplicationContext的创建和刷新的不同阶段的事件,被SpringApplicationRunListener调用,例如ConfigFileApplicationListener订阅ApplicationEnvironmentPreparedEvent加载配置文件
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
图一:默认加载的ApplicationListener以及对应的作用
核心方法
//获取spring.factories下定义的SpringApplicationRunListener,发布SpringApplication启动过程中的各种事件,主要是EventPublishingRunListener来将事件广播到ApplicationListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建Environment,发布ApplicationEnvironmentPreparedEvent,springcloud就是使用BootstrapApplicationListener通过订阅这个事件完成了configserver上配置的加载
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
Banner printedBanner = printBanner(environment);//打印banner
//创建ApplicationContext
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
//调用ApplicationContextInitializer初始化,注入当前启动类的BeanDefinition,完成后beanmap中还只有启动类和AnnotationConfigUtils注入的几个BeanPostProcessor(不考虑springcloud的场景),这个类上声明的Configuration,EnableAutoConfiguration,ComponentScan等被ConfigurationClassPostProcessor处理加载其余的BeanDefinition
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
refreshContext(context);//核心方法,调用Context的refresh方法
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
createApplicationContext:创建ApplicationContext 对于web应用创建AnnotationConfigEmbeddedWebApplicationContext,初始化时调用AnnotationConfigUtils.registerAnnotationConfigProcessors注册常用的BeanPostProcessor:
ConfigurationClassPostProcessor:处理@Configuration CommonAnnotationBeanPostProcessor:处理@Resource、@PostConstruct和@PreDestroy AutowiredAnnotationBeanPostProcessor:处理@Autowired、@Value、@Lookup和@Inject注解的实现 RequiredAnnotationBeanPostProcessor:处理@Required注解 BeanValidationPostProcessor:处理@Min,@NotNull等注解
refreshContext:调用AbstractApplicationContext的refresh方法
// 初始化 refresh 的上下文环境
prepareRefresh();
// 初始化 BeanFactory,加载并解析BeanDefinition,子类实现
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对 BeanFactory 进行功能增强,例如添加ApplicationContextAwareProcessor设置各种Aware实现类的属性。注入一些其它信息的bean,比如environment、systemProperties等
//添加ApplicationListenerDetector,用于探测 ApplicationListener 类型接口
prepareBeanFactory(beanFactory);
try {
// 子类扩展注册BeanDefinition
postProcessBeanFactory(beanFactory);
// BeanFactoryPostProcessor 用于对 BeanFactory 实例进行后置处理,重点包含ConfigurationClassPostProcessor会解析@Configuration注解的类进行注册
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor,主要是AnnotationConfigUtils.registerAnnotationConfigProcessors注册的BeanPostProcessor,如果是通过配置类创建的在上一步已经注册了
registerBeanPostProcessors(beanFactory);
// 初始化国际化资源
initMessageSource();
// 初始化事件广播器
initApplicationEventMulticaster();
// 子类实现,springboot中是EmbeddedWebApplicationContext创建web容器(Tomcat,jetty等)
onRefresh();
//将容器中解析出的ApplicationListener注册到广播器
registerListeners();
// 实例化所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
//发布上下文刷新完毕事件,调用所有实现了 Lifecycle 的 start 方法,调用web服务器的start方法
finishRefresh();
}
图二:invokeBeanFactoryPostProcessors内部的调用流程
图三:ConfigurationClassPostProcessor解析注解加载BeanDefinition的流程
总结:
1,扩展性强:通过ApplicationContextInitializer,SpringApplicationRunListener,SmartApplicationListener(或者EventListener注解)等在应用的启动过程调用自定义行为,例如Spring Cloud就是通过BootstrapApplicationListener订阅ApplicationEnvironmentPreparedEvent在启动过程中实现了外部配置文件的加载
2,灵活:通过Configuration,Import等灵活的实现类注入简化了配置,配合ConfigurationProperties极大的简化了系统的初始化配置
参考:
http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow
http://fangjian0423.github.io/2017/05/10/springboot-context-refresh/
http://www.zhenchao.org/2017/06/03/spring-src-application-context/
Spring Boot启动流程的更多相关文章
- Spring Boot启动流程分析
引言 早在15年的时候就开始用spring boot进行开发了,然而一直就只是用用,并没有深入去了解spring boot是以什么原理怎样工作的,说来也惭愧.今天让我们从spring boot启动开始 ...
- Spring Boot启动流程详解(一)
环境 本文基于Spring Boot版本1.3.3, 使用了spring-boot-starter-web. 配置完成后,编写了代码如下: @SpringBootApplication public ...
- Spring Boot启动流程详解
注:本文转自http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow 环境 本文基于Spring Boot版本1.3.3, 使用了sp ...
- Spring Boot -- 启动流程分析之ApplicationContext 中
上一节我们已经分析到AbsractApplicationContext类refresh方法中的postProcessBeanFactory方法,在分析registerBeanPostProcessor ...
- Spring Boot(三):Spring Boot中的事件的使用 与Spring Boot启动流程(Event 事件 和 Listeners监听器)
前言:在讲述内容之前 希望大家对设计模式有所了解 即使你学会了本片的内容 也不知道什么时候去使用 或者为什么要这样去用 观察者模式: 观察者模式是一种对象行为模式.它定义对象间的一种一对多的依赖关系, ...
- Spring Boot 启动原理分析
https://yq.aliyun.com/articles/6056 转 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启 ...
- Spring Boot启动过程(七):Connector初始化
Connector实例的创建已经在Spring Boot启动过程(四):Spring Boot内嵌Tomcat启动中提到了: Connector是LifecycleMBeanBase的子类,先是设置L ...
- Spring Boot 启动(四) EnvironmentPostProcessor
Spring Boot 启动(四) EnvironmentPostProcessor Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698. ...
- Spring Boot 启动(二) 配置详解
Spring Boot 启动(二) 配置详解 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Boot 配置 ...
随机推荐
- Le Chapitre VIII
J'appris bien vite à mieux connaître cette fleur. Il y avait toujours eu, sur la planète du petit pr ...
- 安装docker跨主机网络flannel
一.实验环境 机器 操作系统 安装服务 172.16.4.36 centos7 docker etcd flannel 172.16.4.37 centos7 docker etcd flanne ( ...
- 微信小程序之下拉加载和上拉刷新
微信小程序下拉加载和上拉刷新两种实现方法 方法一:onPullDownRefresh和onReachBottom方法实现小程序下拉加载和上拉刷新 首先要在json文件里设置window属性 ...
- $.contains(a,b)
jQuery.contains()函数用于判断指定元素内是否包含另一个元素. 简而言之,该函数用于判断另一个DOM元素是否是指定DOM元素的后代. 该函数属于全局jQuery对象. 语法 jQuery ...
- ZUFE2481 神奇的字符串 2017-05-12 16:41 39人阅读 评论(0) 收藏
2481: 神奇的字符串 时间限制: 3 Sec 内存限制: 256 MB 提交: 8 解决: 3 [提交][状态][讨论版] 题目描述 输入 输出 样例输入 abcb 1000 1100 350 ...
- ES版本控制
版本控制 ElasticSearch采用了乐观锁来保证数据的一致性,也就是说,当用户对document进行操作时,并不需要对该doucument作加锁和解锁的操作,只需要指定要操作的版本即可.当版本号 ...
- python 引入本地module
我们经常会遇到调用组内其他成员开发的python脚本的情况, 这时,需要借助如下代码: import sys sys.path.append('/./..') #/./.. 是需要引入的module的 ...
- ElementTriArgyris
class ElementTriArgyris(ElementH2): nodal_dofs = 6 facet_dofs = 1 dim = 2 maxdeg = 5 def gdof(self, ...
- iOS处理视图上同时添加单击与双击手势的冲突问题
_bgView.userInteractionEnabled = YES; //在cell上添加 bgView,给bgView添加两个手势检测方法 UITapGestureRecognizer *do ...
- ASP.NET自定义错误页并返回正确的500、404状态码
在项目中,我们常常需要自定义错误页面,但往往返回的状态码都变成了200,对SEO很不友好.我尝试过在百度上寻找解决方案,但找到的资料中说的方法都试过了,发现都是无法返回正确的状态码的. 最后,只好自已 ...