1、记录一下Springboot启动过程,代码如下:

@SpringBootApplication
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class , args );
        System.out.println("finsh.");
    }
}

2、以上的关键是注解 @SpringBootApplication ,进去里面可以看到是多个注解的集合

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented #注解表明这个注解是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注解了文档化,它的注解成为公共API的一部分。
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

3、其中最为核心的注解为@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

 

这三个,如果我们在启动时不使用@SpringBootApplication来标注,则我们可以使用@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组合来启动,代码如下:

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class StartApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class , args );
        System.out.println("finsh.");
    }
}

Debug一下,追踪一下整个启动过程

 

springboot中注解某个类最后加载 springboot注解加载过程_初始化

springboot中注解某个类最后加载 springboot注解加载过程_初始化_02

 以上代码主要做了几步操作:

1、将source放入SpringApplication的source属性中管理,source是一个LinkedHashSet(),这意味着我们可以同时创建多个自定义不重复的Application,但是目前只有一个

2、this.webApplicationType = WebApplicationType.deduceFromClasspath(); 设置web应用类型

3、从spring.factories中找出ApplicationContextInitializeer并设置初始化器initializers

4、从spring.factories中找出ApplicationListener,并实例化后设置到SpringApplication的监听器listener属性中。这个过程就是找出所有的应用程序时间监听器

5、this.mainApplicationClass = deduceMainApplicationClass(); 找出的main方法的类(这里是StartApplication),并返回Class对象

SpringApplication构造和初始化完成后,运行run方法,

springboot中注解某个类最后加载 springboot注解加载过程_自定义_03

以上代码主要做了几步操作

1、构造一个StopWatch,观察SpringApplication的执行

2、找出所有的SpringApplicationRunListener并封装到SpringApplicationRunListeners中,用于监听run方法的执行。监听的过程中会封装成事件并广播出去让初始化过程中产生的应用程序监听器进行监听

3、创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)

4、遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”

5、Banner printedBanner = printBanner(environment); 如果SpringApplication的showBanner属性被设置为true,则打印banner

6、context = createApplicationContext(); 根据用户是否明确设置了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、refreshContext(context) 调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序

12、 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们

13、正常情况下,遍历执行SpringApplicationRunListener的finished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理)

启动完成

springboot中注解某个类最后加载 springboot注解加载过程_spring boot_04

来都来了,点个赞再走呗~