SpringBoot启动流程简述
Spring Boot程序有⼀个⼊⼝,就是main⽅法。main⾥⾯调⽤SpringApplication.run()启动整个Spring Boot程序,该⽅法所在类需要使⽤@SpringBootApplication注解。
@SpringBootApplication
public class DemoApplication{
public static void main(){
SpringApplication.run(DemoApplication.class,args);
}
}
@SpringBootApplication包括三个注解:
1)@EnableAutoConfiguration:SpringBoot根据应⽤所声明的依赖来对Spring框架进⾏⾃动配置。简单概括⼀下就是借助@Import的帮助,将所有符合⾃动配置条件的bean定义加载到IoC容器。
2)@Configuration:它就是JavaConfig形式的Spring Ioc容器的配置类。被标注的类等于在spring的XML配置⽂件中(l),装配所有bean事务,提供了⼀个spring的上下⽂环境。
3)@CompentScan:组件扫描,可⾃动发现和装配Bean,功能其实就是⾃动扫描并加载符合条件的组件或者 bean定义,最终将这些bean定义加载到Ioc容器中。可以通过basePackages等属性来细粒度的定制@ComponentScan⾃动扫描的范围,如果不指定,则默认Spring框架实现从声明@ComponentScan所在类的package进⾏扫描。默认扫描SpringApplication的run⽅法⾥的Booter.class所在的包路径下⽂件,所以最好将该类放到根路径下。
运⾏run⽅法之前需要对SpringApplication进⾏初始化,会调⽤⼀个private类型的initialize⽅法
public sources){
initialize(sources);
}
initialize⽅法的具体实现:
private void initialize(Object[] sources){
if(sources != null && sources.length >0){
this.sources.addAll(Arrays.asList(sources));// 把sources设置到SpringApplication的sources属性中,⽬前只是⼀个MyApplication类对象
}
this.webEnvironment =deduceWebEnvironment();// 判断是否是web程序(javax.servlet.Servlet和org.t.ConfigurableWebApp licationContext都必须在类加载器中存在),并设置到webEnvironment属性中
// 从spring.factories⽂件中出key为ApplicationContextInitializer的类并实例化后设置到SpringApplication的initializers属性中。这个过程也就是出所有的应⽤程序初始化器
setInitializers((Collection)getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从spring.factories⽂件中出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是出所有的应⽤程序事件
springboot是啥setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
// 出main类,这⾥是MyApplication类
this.mainApplicationClass =deduceMainApplicationClass();
}
SpringBoot启动的时候,不论调⽤什么⽅法,都会构造⼀个SpringApplication的实例,然后调⽤这个实例的run⽅法,这样就表⽰启动SpringBoot。
在run⽅法调⽤之前,也就是构造SpringApplication的时候进⾏初始化⼯作,初始化的时候会做以下⼏件事:
1,把参数sources设置到SpringApplication设置中,这个sources可以是任何类型的参数。
2,判断是否是web程序,并设置到webEnvironment这个boolean属性中。
3,出所有的初始化器,默认有5个,设置到initializers属性中。
4,出所有的应⽤程序,默认有9个,设置到listenrs属性中。
5,出运⾏的主类(main class)。
SpringApplication构造完成之后会调⽤run⽅法,启动SpringApplication,run⽅法执⾏的时候会做以下⼏件事:
1,构造⼀个stopWatch,观察SpringApplication的执⾏。
2,出所有的SpringApplicationRunListeners中,⽤于监听run⽅法的执⾏。监听的过程中会封装成事件并⼴播出去让初始化过程中产⽣的应⽤程序进⾏监听。
3,构造Spring容器(ApplicationContext),并返回
3.1 创建Spring容器的判断是否是web环境,是的话构造AnnotationConfigEmbeddedWebApplicationContext,否则构造AnnotationConfigApplicationContext。
3.2 初始化过程中产⽣的初始化容器在这个时候开始⼯作。
3.3 Spring容器的刷新(完成bean的解析、各种processor接⼝的执⾏、条件注解的解析等等)。
4,从Spring容器中出ApplicationRunner和CommandLineRunner接⼝的实现类并排序后依次执⾏。
引⽤另⼀版本的解释:
SpringApplication的run⽅法的实现是我们本次旅程的主要线路,该⽅法的主要流程⼤体可以归纳如下:
1) 如果我们使⽤的是SpringApplication的静态run⽅法,那么,这个⽅法⾥⾯⾸先要创建⼀个SpringApplication对象实例,然后调⽤这个创建好的SpringApplication的实例⽅法。在SpringApplication实例初始化的时候,它会提前做⼏件事情:
根据classpath⾥⾯是否存在某个特征类(org.t.ConfigurableWebApplicationContext)来决定是否应该创建⼀个为Web应⽤使⽤的ApplicationContext类型。
使⽤SpringFactoriesLoader在应⽤的classpath中查并加载所有可⽤的ApplicationContextInitializer。
使⽤SpringFactoriesLoader在应⽤的classpath中查并加载所有可⽤的ApplicationListener。
推断并设置main⽅法的定义类。
2) SpringApplication实例初始化完成并且完成设置后,就开始执⾏run⽅法的逻辑了,⽅法执⾏伊始,
⾸先遍历执⾏所有通过SpringFactoriesLoader可以查到并加载的SpringApplicationRunListener。调⽤它们的started()⽅法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应⽤要开始执⾏咯!”。
3) 创建并配置当前Spring Boot应⽤将要使⽤的Environment(包括配置要使⽤的PropertySource以及Profile)。
4) 遍历调⽤所有SpringApplicationRunListener的environmentPrepared()的⽅法,告诉他们:“当前SpringBoot应⽤使⽤的Environment准备好了咯!”。
5) 如果SpringApplication的showBanner属性被设置为true,则打印banner。
6) 根据⽤户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应⽤创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使⽤⾃定义的BeanNameGenerator,决定是否使⽤⾃定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使⽤。
7) ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查并加
载classpath中所有可⽤的ApplicationContext-Initializer,然后遍历调⽤这些ApplicationContextInitializer的initialize(applicationContext)⽅法来对已经创建好的ApplicationContext进⾏进⼀步的处理。
8) 遍历调⽤所有SpringApplicationRunListener的contextPrepared()⽅法。
9) 最核⼼的⼀步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。
10) 遍历调⽤所有SpringApplicationRunListener的contextLoaded()⽅法。
11) 调⽤ApplicationContext的refresh()⽅法,完成IoC容器可⽤的最后⼀道⼯序。
12) 查当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执⾏它们。
13) 正常情况下,遍历执⾏SpringApplicationRunListener的finished()⽅法、(如果整个过程出现异常,则依然调⽤所有SpringApplicationRunListener的finished()⽅法,只不过这种情况下会将异常信息⼀并传⼊处理)
去除事件通知点后,整个流程如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论