面试官:知道 springboot 的启动原理吗?( 二 )

我们这里大概梳理一下启动过程的步骤:
1. 初始化监听器,以及添加到SpringApplication的自定义监听器 。2. 发布ApplicationStartedEvent事件,如果想监听ApplicationStartedEvent事件,你可以这样定义:public class ApplicationStartedListener implements ApplicationListener,然后通过SpringApplication.addListener(..)添加进去即可 。3. 装配参数和环境,确定是web环境还是非web环境 。4. 装配完环境后,就触发ApplicationEnvironmentPreparedEvent事件 。5. 如果SpringApplication的showBanner属性被设置为true,则打印启动的Banner 。6. 创建ApplicationContext,会根据是否是web环境,来决定创建什么类型的ApplicationContext 。7. 装配Context的环境变量,注册Initializers、beanNameGenerator等 。8. 发布ApplicationPreparedEvent事件 。9. 注册springApplicationArguments、springBootBanner,加载资源等10. 遍历调用所有SpringApplicationRunListener的contextLoaded()方法 。11. 调用ApplicationContext的refresh()方法,装配context beanfactory等非常重要的核心组件 。12. 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们 。13. 发布ApplicationReadyEvent事件,启动完毕,表示服务已经可以开始正常提供服务了 。通常我们这里会监听这个事件来打印一些监控性质的日志,表示应用正常启动了 。

面试官:知道 springboot 的启动原理吗?

文章插图
 
启动流程
@SpringBootApplication 注解看完了静态方法,我们来看一下另一个注解 @SpringBootApplication 。
注解定义@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = {        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {    // 省略方法}我们省略掉对应的方法属性,发现实际上这个注解是由 3 个注解组合而成:
@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan其中 @SpringbootConfiguration 是完全等价于 @Configuration 的,此处应该是为了和 spring 的注解做区分 。
所以一开始的实现,等价于:
@Configuration@EnableAutoConfiguration@ComponentScanpublic class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}当然了,springboot 的理念就是极简配置,能少写一行代码,就少写一行代码!
@Configuration 注解这里的 @Configuration 大家应该并不陌生,spring 中可以使用下面的写法,替代 spring xml 的配置写法:
@Configurationpublic class MockConfiguration{    @Bean    public MockService mockService(){        return new MockServiceImpl(dependencyService());    }    @Bean    public DependencyService dependencyService(){        return new DependencyServiceImpl();    }}@ComponentScan 注解@ComponentScan 的功能其实就是自动扫描并加载符合条件的组件(比如 @Component 和 @Service等)或者bean定义,最终将这些bean定义加载到IoC容器中 。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明 @ComponentScan 所在类的package进行扫描 。
ps: 所以我们的 Application 启动类一般是放在根目录,这样连扫描的包也省略掉了 。
@EnableAutoConfiguration 注解这个注解我们放在最后讲解,因为它为 springboot 带来了更多的便利性 。
注解定义@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(EnableAutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {}这个注解实际上是一个组合注解 @AutoConfigurationPackage + @Import
@AutoConfigurationPackage:自动配置包
@Import: 导入自动配置的组件
我们来看一下这 2 个注解:


推荐阅读