Springboot的启动过程总结
1、总体步骤分两个
创建Spring 应⽤(创建SpringApplication)
运⾏Spring 应⽤(运⾏SpringApplication)
2、创建Spring 应⽤(创建SpringApplication)
就是new ⼀个对象,构造器⾥⾯做⼀些初始化的动作
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断应⽤的类型deduce v.  推论; 推断; 演绎;的意思
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置初始化器,保存起来从spring.factories
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置、保存起来从spring.factories
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//主应⽤类是那个
this.mainApplicationClass = deduceMainApplicationClass();
}
3、运⾏Spring 应⽤(运⾏SpringApplication)
// args 就是我们java-jar 时传的命令⾏参数
public ConfigurableApplicationContext args) {
StopWatch stopWatch = new StopWatch();
spring启动流程面试回答stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//设置应⽤进⼊Headless 模式
configureHeadlessProperty();
//获取所有的运⾏:就⼀个EventPublishingRunListener从spring.factories 中的
SpringApplicationRunListeners listeners = getRunListeners(args);
//通知对系统启动过程中的⼈,项⽬正在启动,让所有的感知到项⽬正在启动,这⾥就包括我们⾃⼰定义的
listeners.starting();
try {
//保存我们传过来的命令⾏参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境,
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//创建IOC容器,这⾥⾄关重要。这个没有特别的,根绝应⽤的类型来创建⼀个SERVLET容器
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备ioc 容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新ioc 容器
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//通知所有的应⽤启动完成了
listeners.started(context);
//获取容器中的ApplicationRunner 和CommandLineRunner ,然后遍历所有的runner,执⾏runner的run⽅法,runner⼀般都是我们⾃⼰写的  callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//调⽤所有的running ⽅法,对程序运⾏过程进⾏监听。
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
return context;
}
3.1 prepareEnvironment ⽅法说明
在这⼀步,SpringApplication会创建Spring启动所需的环境,这个环境主要由ConfigurableEnviroment对象表⽰。
⾸先,该对象确认了程序是否需要设置Web环境,其次,该对象还确定了程序所需要的参数和读取的配置⽂件等信息。
/**
*
*  获取或者创建⼀个Environment对象,如果我们⾃⼰在main ⽅法⾥⾯创建了⼀个Environment,并放到
*        SpringApplication 中了就不创建了,
*        SpringApplication application = new SpringApplication(ProfileDemoApplication.class);
*        ConfigurableEnvironment environment = new StandardEnvironment();
*        environment.setActiveProfiles("dev");
*        application.setEnvironment(environment);
*  否则就创建
*
*
*/
注意:以下的说明
// 添加初始的properties(注意:当前并未加载如application.properties/yml的properties)
/
/ 添加初始的profile(注意:当前并未加载如application.properties/yml配置profile)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//创建或者获取⼀个Environment 对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置environment
configureEnvironment(environment, SourceArgs());
ConfigurationPropertySources.attach(environment);
// 触发(主要是触发ConfigFileApplicationListener,这个将会加载如application.properties/yml这样的配置⽂件)
//通知所有的环境准备好了,包括我门⾃⼰定义的。
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
return environment;
}
3.1.1 configureEnvironment
//配置环境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
ConversionService conversionService = SharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
//把命令⾏参数、外部配置⽂件的属性(利⽤@PropertySource指定的⽂件),系统属性都配置到环境⾥⾯、加载配置⽂件
//激活profile环境的
}
3.2 prepareContext
/**
*
*
* 虽然已经得到了ApplicationContext对象,但此时的对象还只是⼀个空⽩对象,需要准备和处理后,ApplicationContext才能被使⽤。
*
* 在准备过程中主要做了做了⼏件事:
* 为ApplicationContext设置之前准备好的Environment对象、也就是说把Environment 组件放到容器⾥⾯
*
* 通过对ApplicationContext后置处理或是BeanDefinitionLoader等⽅式往容器中添加⼀些初始的Bean。
*
* 应⽤默认的初始化器初始化应⽤程序上下⽂(责任链模式的应⽤,多个初始化器形成⼀个List,应⽤程序需要被每个初始化器应⽤⼀次,每个初始化器有⾃⼰的职责)。 *
* 准备过程中ApplicationRunListener发出两个消息,分别是contextPrepared和contextLoaded。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 给上下⽂对象设置环境对象,给AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner设置环境对象    context.setEnvironment(environment);
// 1. 上下⽂后置处理,包括向BeanFactory中注册BeanNameGenerator和ConversionService
postProcessApplicationContext(context);
// 2. SpringApplication构造器中初始化了各种ApplicationContextInitializer(应⽤初试化器),
//循环调⽤他们的initialize⽅法、对ioc 容器进⾏扩展
applyInitializers(context);
// 遍历所有的,通知上下⽂准备好了。
if (this.logStartupInfo) {
// 打印启动信息,包括pid,⽤户等
Parent() == null);
// 答应profile信息
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = BeanFactory();
// 将命令⾏参数组件注册到容器⾥⾯
if (printedBanner != null) {
// 将Banner注册到容器中
}
if (beanFactory instanceof DefaultListableBeanFactory) {
// 设置不允许定义同名的BeanDefinition,重复注册时抛出异常
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
// 如果懒加载,添加懒加载后置处理器
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
load(context, Array(new Object[0]));
//遍历所有的,IOC容器加载好了
}
3.3 refreshContext()——刷新上下⽂
在应⽤程序上下⽂准备好后,可以通过刷新应⽤程序上下⽂发现Bean并加载到容器中,主要是⽬的是加载bean refreshContext()会调⽤fresh()⽅法。
AbstractApplicationContext中定义了refresh()⽅法的基本框架(模板模式的应⽤)。
3.3.1 refresh()
这个是spring经典的容器初始化过程,创建所有的组件

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。