springboot启动原理

springboot启动原理

@Target({ElementType.TYPE})  //注解的适用范围,其中TYPE用于描述类,接口(包括包注解类型)活enum声明
@Retention(RetentionPolicy.RUNTIME)//注解的生命周期,保留到class文件中(三个生命周期)
@Documented  //  表明这个注解应该被javadoc记录
@Inherited  // 子类可以继承该注解
// 以上四个注解是java注解的元注解,不做说明
@SpringBootConfiguration   // 继承了Configuration,表示当前是注解类
@EnableAutoConfiguration   // 开启springboot 的注解功能,springboot的四大神器之一,其中借助了@import的帮助
@ComponentScan(      // 扫描路径设置
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    ...
}

上面定义的注解中最重要的是

  • @SpringBootConfiguration // 继承了Configuration,表示当前是注解类
  • @EnableAutoConfiguration // 开启springboot 的注解功能,springboot的四大神器之一,其中借助了@import的帮助
  • @ComponentScan
@Configuration

springIOC容器的配置类,任何一个标注了@Configuration的java类都是一个javaConfig配置类

任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IOC容器中,方法名默认为该bean定义的id。

如果一个bean的定义依赖其他bean,则直接调用对应的javaConfig类中依赖bean的创建方法就可以了。

@ComponentScan

@ComponentScan这个注解就是自动扫描加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到Ioc容器中。

我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认spring框架实现会从声明@ComponentScan所在类的package进行扫描。

(这也就是为什么springboot 的启动类最好放在root package路径下的原因,因为默认不指定basePackages)

@EnableAutoConfiguration

借助@Import,将所有符合自动配置条件的bean定义加载到Ioc容器中。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 以上四个注解是java注解的元注解,不做说明
@AutoConfigurationPackage  //  自动配置包
@Import({AutoConfigurationImportSelector.class})  //  导入自动配置的组件
public @interface EnableAutoConfiguration {
    ...
}

以上代码中,最重要的就是**@Import({AutoConfigurationImportSelector.class})** ,借助AutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助springboot应用将所有符合条件的配置都加载到当前SpringBoot创建并使用的Ioc容器。借助SpringFactoriesLoader工具类的支持,@EnableAutoConfiguration可以智能的自动配置。

由以上的分析可知,自动配置的幕后英雄是SpringFactoriesLoader

SpringFactoriesLoader 分析

先来看看该类定义是什么样子的

public final class SpringFactoriesLoader {
// 最耀眼的属性, 定义了一个文件路径 META-INF/spring.factories
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
...   
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
 ...
}
private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) {
... 
    }
}

找到这个文件在这里插入图片描述

该配置文件中最后的类名都是XXXAutoConfiguration,然后就是配合@EnableAutoConfiguration注解,拿着配置文件中定义好的类名通过反射实例化为对应的标注了@Configuration的JavaConfig,形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

总结SpringApplication的执行流程

通过查看源码,我们知道SpringBoot应用的执行入口是run方法。我们也是从该方法入手的。大体的流程如下:

  • 如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication

    的实例,然后调用这个创建好的SpringApplication是实例方法。

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
   return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
     return (new SpringApplication(primarySources)).run(args);
}

根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。

推断并设置main方法的定义类。

  • SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。
  • 创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。
  • 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。
  • 如果SpringApplication的showBanner属性被设置为true,则打印banner。
  • 根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
  • ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。
  • 遍历调用所有SpringApplicationRunListener的contextPrepared()方法。
  • 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。
  • 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
  • 调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。
  • 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。

以上就是SpringBoot的启动流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值