[springboot]springboot启动流程
Spring Boot程序有⼀个⼊⼝,就是main⽅法。main⾥⾯调⽤SpringApplication.run()启动整个Spring Boot程序,该⽅法所在类需要使⽤@SpringBootApplication复合注解。
1、@SpringBootApplication注解的组成
@EnableAutoConfiguration
@EnableAutoConfiguration是借助@Import的帮助,将所有符合⾃动配置条件的bean定义加载到IoC容器
在这个注解中,最重要的是它导⼊了⼀个类EnableAutoConfigurationImportSelector,它是⼀个ImportSelector接⼝的实现类
Spring Boot在启动时,在classpath下所有的META-INF/spring.factories⽂件中根据@EnableAutoConfiguration的完整类名
org.springframework.boot.autoconfig.EnableAutoConfiguration作为查的Key,获得对应的⼀组@Configuration类,并将其封装到⼀个List中返回。(spring.factories是⼀个典型的java properties⽂件,只不过Key和Value都是Java类型的完整类名)
通过 filter 过滤掉当前环境不需要⾃动装配的类,⽐如没有集成RabbitMQ,就不需要,或者有的条件@Conditional不满⾜也不需要⾃动装配
将需要⾃动装配的全路径类名注册到 SpringIOC 容器,⾃此 SpringBoot ⾃动装配完成!
@SpringBootConfiguration
该注解作⽤就是将当前的类作为⼀个JavaConfig,然后触发注解@EnableAutoConfiguration和@ComponentScan的处理,本质上与@Configuration注解没有区别。
@ComponentScan
@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是⾃动扫描并加载符合条件的组件(⽐如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan⾃动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进⾏扫描。
注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。
2、SpringBoot启动流程
1、SpringBoot启动的时候,会构造⼀个SpringApplication的实例,然后调⽤这个实例的run⽅法,在run⽅法调⽤之前,也就是构造SpringApplication的时候会进⾏初始化的⼯作,初始化的时候会做以下⼏件事:
1. 把参数sources设置到SpringApplication属性中,这个sources可以是任何类型的参数.
2. 判断是否是web程序,并设置到webEnvironment的boolean属性中.
3. 创建并初始化ApplicationInitializer,设置到initializers属性中 。
4. 创建并初始化ApplicationListener,设置到listeners属性中 。
5. 初始化主类mainApplicatioClass。
源代码:
private void initialize(Object[] sources){
if(sources !=null&& sources.length >0){
//把sources设置到SpringApplication的sources属性中,⽬前只是⼀个MyApplication类对象
this.sources.addAll(Arrays.asList(sources));
}
//判断是否是web程序,并设置到webEnvironment的boolean属性中
this.webEnvironment =deduceWebEnvironment();
//出所有的初始化器,默认有5个,设置到initializers属性中。
setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
//出所有的应⽤程序,默认有9个,设置到listeners属性中。
setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
//出运⾏的主类(main class)
this.mainApplicationClass =deduceMainApplicationClass();
}
2、SpringApplication构造完成之后调⽤run⽅法,启动SpringApplication,run⽅法执⾏的时候会做以下⼏件事:
1. 构造⼀个StopWatch计时器,⽤来记录SpringBoot的启动时间 。
2. 获取SpringApplicationRunListeners并封装到SpringApplicationRunListeners中启动,⽤于监听run⽅法的执⾏。
3. 创建并初始化ApplicationArguments,获取run⽅法传递的args参数。
4. 创建并初始化ConfigurableEnvironment(环境配置)。
5. 打印banner和版本。
6. 构造Spring容器(ApplicationContext)上下⽂。
7. SpringApplicationRunListeners发布finish事件。
8. StopWatch计时器停⽌计时,⽇志打印总共启动的时间。
9. 发布SpringBoot程序已启动事件(started())
10. 调⽤ApplicationRunner和CommandLineRunner
11. 最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了(running())
public ConfigurableApplicationContext args){
// 创建⼀个StopWatch实例,⽤来记录SpringBoot的启动时间
StopWatch stopWatch =new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context =null;
Collection<SpringBootExceptionReporter> exceptionReporters =new ArrayList<>();
configureHeadlessProperty();
// 通过SpringFactoriesLoader加载listeners:⽐如EventPublishingRunListener
SpringApplicationRunListeners listeners =getRunListeners(args);
// 发布SprintBoot启动事件:ApplicationStartingEvent
listeners.starting();
try{
ApplicationArguments applicationArguments =new DefaultApplicationArguments(args);
// 创建和配置environment,发布事件:SpringApplicationRunListeners#environmentPrepared
ConfigurableEnvironment environment =prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment);
// 打印SpringBoot的banner和版本
Banner printedBanner =printBanner(environment);
// 创建对应的ApplicationContext:Web类型,Reactive类型,普通的类型(⾮Web)
context =createApplicationContext();
exceptionReporters =getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ ConfigurableApplicationContext.class}, context);
// 准备ApplicationContext,Initializers设置到ApplicationContext后发布事件:ApplicationContextInitializedEvent
// 打印启动⽇志,打印profile信息(如dev, test, prod)
// 调⽤EventPublishingRunListener发布ApplicationContext加载完毕事件:ApplicationPreparedEvent
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 最终会调⽤到AbstractApplicationContext#refresh⽅法,实际上就是Spring IOC容器的创建过程,并且会进⾏⾃动装配的操作// 以及发布ApplicationContext已经refresh事件,标志着ApplicationContext初始化完成springboot框架是干嘛的
refreshContext(context);
// hook⽅法
afterRefresh(context, applicationArguments);
// stopWatch停⽌计时,⽇志打印总共启动的时间
stopWatch.stop();
if(this.logStartupInfo){
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 发布SpringBoot程序已启动事件ApplicationStartedEvent
listeners.started(context);
// 调⽤ApplicationRunner和CommandLineRunner
callRunners(context, applicationArguments);
}
catch(Throwable ex){
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try{
// 最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了
listeners.running(context);
}
catch(Throwable ex){
handleRunFailure(context, ex, exceptionReporters,null);
throw new IllegalStateException(ex);
}
return context;
}

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