当前位置:   article > 正文

SpringBoot 源码解析笔记_getbootstrapregistryinitializersfromspringfactorie

getbootstrapregistryinitializersfromspringfactories

欢迎各位关注我的笔记仓库,clone 仓库到本地后使用 Typora 阅读效果更好。

如果大家只关注 SpringBoot 如何自动装配,可以只看“注解分析”和“装配流程”两个小节


启动流程

应用启动:

  1. @SpringBootApplication
  2. public class BootApplication {
  3. public static void main(String[] args) {
  4. // 启动代码
  5. SpringApplication.run(BootApplication.class, args);
  6. }
  7. }

SpringApplication 构造方法:

  • this.resourceLoader = resourceLoader:资源加载器,初始为 null

  • this.webApplicationType = WebApplicationType.deduceFromClasspath():判断当前应用的类型,是响应式还是 Web 类

  • this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories()获取引导器

    • 去 META-INF/spring.factories 文件中找 org.springframework.boot.Bootstrapper
    • 寻找的顺序:classpath → spring-beans → boot-devtools → springboot → boot-autoconfigure
  • setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class))获取初始化器

    • 去 META-INF/spring.factories 文件中找 org.springframework.context.ApplicationContextInitializer
  • setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))获取监听器

    • 去 META-INF/spring.factories 文件中找 org.springframework.context.ApplicationListener
  • this.mainApplicationClass = deduceMainApplicationClass():获取出 main 程序类

SpringApplication#run(String... args):

  • StopWatch stopWatch = new StopWatch():停止监听器,监控整个应用的启停

  • stopWatch.start():记录应用的启动时间

  • bootstrapContext = createBootstrapContext()创建引导上下文环境

    • bootstrapContext = new DefaultBootstrapContext():创建默认的引导类环境
    • this.bootstrapRegistryInitializers.forEach():遍历所有的引导器调用 initialize 方法完成初始化设置
  • configureHeadlessProperty():让当前应用进入 headless 模式

  • listeners = getRunListeners(args):获取所有 RunListener(运行监听器)

    • 去 META-INF/spring.factories 文件中找 org.springframework.boot.SpringApplicationRunListener
  • listeners.starting(bootstrapContext, this.mainApplicationClass)遍历所有的运行监听器调用 starting 方法

  • applicationArguments = new DefaultApplicationArguments(args):获取所有的命令行参数

  • environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments)准备环境

    • environment = getOrCreateEnvironment():返回或创建基础环境信息对象

      • switch (this.webApplicationType):根据当前应用的类型创建环境
        • case SERVLET:Web 应用环境对应 ApplicationServletEnvironment
        • case REACTIVE:响应式编程对应 ApplicationReactiveWebEnvironment
        • default:默认为 Spring 环境 ApplicationEnvironment
    • configureEnvironment(environment, applicationArguments.getSourceArgs()):读取所有配置源的属性值配置环境

    • ConfigurationPropertySources.attach(environment):属性值绑定环境信息

      • sources.addFirst(ATTACHED_PROPERTY_SOURCE_NAME,..):把 configurationProperties 放入环境的属性信息头部
    • listeners.environmentPrepared(bootstrapContext, environment)运行监听器调用 environmentPrepared(),EventPublishingRunListener 发布事件通知所有的监听器当前环境准备完成

    • DefaultPropertiesPropertySource.moveToEnd(environment):移动 defaultProperties 属性源到环境中的最后一个源

    • bindToSpringApplication(environment):与容器绑定当前环境

    • ConfigurationPropertySources.attach(environment):重新将属性值绑定环境信息

      • sources.remove(ATTACHED_PROPERTY_SOURCE_NAME):从环境信息中移除 configurationProperties

      • sources.addFirst(ATTACHED_PROPERTY_SOURCE_NAME,..):把 configurationProperties 重新放入环境信息

  • configureIgnoreBeanInfo(environment):配置忽略的 bean

  • printedBanner = printBanner(environment):打印 SpringBoot 标志

  • context = createApplicationContext()创建 IOC 容器

    switch (this.webApplicationType):根据当前应用的类型创建 IOC 容器

    • case SERVLET:Web 应用环境对应 AnnotationConfigServletWebServerApplicationContext
    • case REACTIVE:响应式编程对应 AnnotationConfigReactiveWebServerApplicationContext
    • default:默认为 Spring 环境 AnnotationConfigApplicationContext
  • context.setApplicationStartup(this.applicationStartup):设置一个启动器

  • prepareContext():配置 IOC 容器的基本信息

    • postProcessApplicationContext(context):后置处理流程

    • applyInitializers(context):获取所有的初始化器调用 initialize() 方法进行初始化

    • listeners.contextPrepared(context):所有的运行监听器调用 environmentPrepared() 方法,EventPublishingRunListener 发布事件通知 IOC 容器准备完成

    • listeners.contextLoaded(context):所有的运行监听器调用 contextLoaded() 方法,通知 IOC 加载完成

  • refreshContext(context)刷新 IOC 容器

    • Spring 的容器启动流程
    • invokeBeanFactoryPostProcessors(beanFactory)实现了自动装配
    • onRefresh()创建 WebServer 使用该接口
  • afterRefresh(context, applicationArguments):留给用户自定义容器刷新完成后的处理逻辑

  • stopWatch.stop():记录应用启动完成的时间

  • callRunners(context, applicationArguments):调用所有 runners

  • listeners.started(context):所有的运行监听器调用 started() 方法

  • listeners.running(context):所有的运行监听器调用 running() 方法

    • 获取容器中的 ApplicationRunner、CommandLineRunner

    • AnnotationAwareOrderComparator.sort(runners):合并所有 runner 并且按照 @Order 进行排序

    • callRunner():遍历所有的 runner,调用 run 方法

  • handleRunFailure(context, ex, listeners)处理异常,出现异常进入该逻辑

    • handleExitCode(context, exception):处理错误代码
    • listeners.failed(context, exception):运行监听器调用 failed() 方法
    • reportFailure(getExceptionReporters(context), exception):通知异常

注解分析

SpringBoot 定义了一套接口规范,这套规范规定 SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器,并执行类中定义的各种操作,对于外部的 jar 包,直接引入一个 starter 即可

@SpringBootApplication 注解是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合

  • @SpringBootApplication 注解

    1. @Inherited
    2. @SpringBootConfiguration //代表 @SpringBootApplication 拥有了该注解的功能
    3. @EnableAutoConfiguration //同理
    4. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    5. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    6. // 扫描被 @Component (@Service,@Controller)注解的 bean,容器中将排除TypeExcludeFilter 和 AutoConfigurationExcludeFilter
    7. public @interface SpringBootApplication { }
  • @SpringBootConfiguration 注解:

    1. @Configuration // 代表是配置类
    2. @Indexed
    3. public @interface SpringBootConfiguration {
    4. @AliasFor(annotation = Configuration.class)
    5. boolean proxyBeanMethods() default true;
    6. }

    @AliasFor 注解:表示别名,可以注解到自定义注解的两个属性上表示这两个互为别名,两个属性其实是同一个含义相互替代

  • @ComponentScan 注解:默认扫描当前包及其子级包下的所有文件

  • @EnableAutoConfiguration 注解:启用 SpringBoot 的自动配置机制

    1. @AutoConfigurationPackage
    2. @Import(AutoConfigurationImportSelector.class)
    3. public @interface EnableAutoConfiguration {
    4. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    5. Class<?>[] exclude() default {};
    6. String[] excludeName() default {};
    7. }
    • @AutoConfigurationPackage:将添加该注解的类所在的 package 作为自动配置 package 进行管理,把启动类所在的包设置一次,为了给各种自动配置的第三方库扫描用,比如带 @Mapper 注解的类,Spring 自身是不能识别的,但自动配置的 Mybatis 需要扫描用到,而 ComponentScan 只是用来扫描注解类,并没有提供接口给三方使用

      1. @Import(AutoConfigurationPackages.Registrar.class) // 利用 Registrar 给容器中导入组件
      2. public @interface AutoConfigurationPackage {
      3. String[] basePackages() default {}; //自动配置包,指定了配置类的包
      4. Class<?>[] basePackageClasses() default {};
      5. }

      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0])):注册 BD

      • new PackageImports(metadata).getPackageNames():获取添加当前注解的类的所在包
      • registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames)):存放到容器中
        • new BasePackagesBeanDefinition(packageNames):把当前主类所在的包名封装到该对象中
    • @Import(AutoConfigurationImportSelector.class):首先自动装配的核心类

      容器刷新时执行:invokeBeanFactoryPostProcessors() → invokeBeanDefinitionRegistryPostProcessors() → postProcessBeanDefinitionRegistry() → processConfigBeanDefinitions() → parse() → process() → processGroupImports() → getImports() → process() → AutoConfigurationImportSelector#getAutoConfigurationEntry()

      1. protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
      2. if (!isEnabled(annotationMetadata)) {
      3. return EMPTY_ENTRY;
      4. }
      5. // 获取注解属性,@SpringBootApplication 注解的 exclude 属性和 excludeName 属性
      6. AnnotationAttributes attributes = getAttributes(annotationMetadata);
      7. // 获取所有需要自动装配的候选项
      8. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
      9. // 去除重复的选项
      10. configurations = removeDuplicates(configurations);
      11. // 获取注解配置的排除的自动装配类
      12. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
      13. checkExcludedClasses(configurations, exclusions);
      14. // 移除所有的配置的不需要自动装配的类
      15. configurations.removeAll(exclusions);
      16. // 过滤,条件装配
      17. configurations = getConfigurationClassFilter().filter(configurations);
      18. // 获取 AutoConfigurationImportListener 类的监听器调用 onAutoConfigurationImportEvent 方法
      19. fireAutoConfigurationImportEvents(configurations, exclusions);
      20. // 包装成 AutoConfigurationEntry 返回
      21. return new AutoConfigurationEntry(configurations, exclusions);
      22. }

      AutoConfigurationImportSelector#getCandidateConfigurations:获取自动配置的候选项

      • List<String> configurations = SpringFactoriesLoader.loadFactoryNames():加载自动配置类

        参数一:getSpringFactoriesLoaderFactoryClass() 获取 @EnableAutoConfiguration 注解类

        参数二:getBeanClassLoader() 获取类加载器

        • factoryTypeName = factoryType.getName():@EnableAutoConfiguration 注解的全类名
        • return loadSpringFactories(classLoaderToUse).getOrDefault():加载资源
          • urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION):获取资源类
          • FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"加载的资源的位置
      • return configurations:返回所有自动装配类的候选项

    • 从 spring-boot-autoconfigure-2.5.3.jar/META-INF/spring.factories 文件中获取自动装配类,进行条件装配,按需装配


装配流程

Spring Boot 通过 @EnableAutoConfiguration 开启自动装配,通过 SpringFactoriesLoader 加载 META-INF/spring.factories 中的自动配置类实现自动装配,自动配置类其实就是通过 @Conditional 注解按需加载的配置类(JVM 类加载机制),想要其生效必须引入 spring-boot-starter-xxx 包实现起步依赖

  • SpringBoot 先加载所有的自动配置类 xxxxxAutoConfiguration
  • 每个自动配置类进行条件装配,默认都会绑定配置文件指定的值(xxxProperties 和配置文件进行了绑定)
  • SpringBoot 默认会在底层配好所有的组件,如果用户自己配置了以用户的优先
  • 定制化配置:
    • 用户可以使用 @Bean 新建自己的组件来替换底层的组件
    • 用户可以去看这个组件是获取的配置文件前缀值,在配置文件中修改

以 DispatcherServletAutoConfiguration 为例:

  1. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  2. // 类中的 Bean 默认不是单例
  3. @Configuration(proxyBeanMethods = false)
  4. @ConditionalOnWebApplication(type = Type.SERVLET)
  5. // 条件装配,环境中有 DispatcherServlet 类才进行自动装配
  6. @ConditionalOnClass(DispatcherServlet.class)
  7. @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
  8. public class DispatcherServletAutoConfiguration {
  9. // 注册的 DispatcherServlet 的 BeanName
  10. public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
  11. @Configuration(proxyBeanMethods = false)
  12. @Conditional(DefaultDispatcherServletCondition.class)
  13. @ConditionalOnClass(ServletRegistration.class)
  14. // 绑定配置文件的属性,从配置文件中获取配置项
  15. @EnableConfigurationProperties(WebMvcProperties.class)
  16. protected static class DispatcherServletConfiguration {
  17. // 给容器注册一个 DispatcherServlet,起名字为 dispatcherServlet
  18. @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  19. public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
  20. // 新建一个 DispatcherServlet 设置相关属性
  21. DispatcherServlet dispatcherServlet = new DispatcherServlet();
  22. // spring.mvc 中的配置项获取注入,没有就填充默认值
  23. dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
  24. // ......
  25. // 返回该对象注册到容器内
  26. return dispatcherServlet;
  27. }
  28. @Bean
  29. // 容器中有这个类型组件才进行装配
  30. @ConditionalOnBean(MultipartResolver.class)
  31. // 容器中没有这个名字 multipartResolver 的组件
  32. @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
  33. // 方法名就是 BeanName
  34. public MultipartResolver multipartResolver(MultipartResolver resolver) {
  35. // 给 @Bean 标注的方法传入了对象参数,这个参数就会从容器中找,因为用户自定义了该类型,以用户配置的优先
  36. // 但是名字不符合规范,所以获取到该 Bean 并返回到容器一个规范的名称:multipartResolver
  37. return resolver;
  38. }
  39. }
  40. }
  1. //将配置文件中的 spring.mvc 前缀的属性与该类绑定
  2. @ConfigurationProperties(prefix = "spring.mvc")
  3. public class WebMvcProperties { }

内嵌容器

(补充内容,WebServer)

SpringBoot 嵌入式 Servlet 容器,默认支持的 webServe:Tomcat、Jetty、Undertow

配置方式:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <exclusions>
  5. <exclusion> <!--必须要把内嵌的 Tomcat 容器-->
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-tomcat</artifactId>
  8. </exclusion>
  9. </exclusions>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-jetty</artifactId>
  14. </dependency>

创建 Web 容器:

  • SpringApplication.run(BootApplication.class, args):应用启动

  • ConfigurableApplicationContext.run()

    • context = createApplicationContext()创建容器

      • applicationContextFactory = ApplicationContextFactory.DEFAULT

        1. ApplicationContextFactory DEFAULT = (webApplicationType) -> {
        2. try {
        3. switch (webApplicationType) {
        4. case SERVLET:
        5. // Servlet 容器,继承自 ServletWebServerApplicationContext
        6. return new AnnotationConfigServletWebServerApplicationContext();
        7. case REACTIVE:
        8. // 响应式编程
        9. return new AnnotationConfigReactiveWebServerApplicationContext();
        10. default:
        11. // 普通 Spring 容器
        12. return new AnnotationConfigApplicationContext();
        13. }
        14. } catch (Exception ex) {
        15. throw new IllegalStateException();
        16. }
        17. }
      • applicationContextFactory.create(this.webApplicationType):根据应用类型创建容器

    • refreshContext(context):容器启动

内嵌容器工作流程:

  • Web 应用启动,SpringBoot 导入 Web 场景包 tomcat,创建一个 Web 版的 IOC 容器 ServletWebServerApplicationContext
  • ServletWebServerApplicationContext 容器启动时进入 refresh() 逻辑,Spring 容器启动逻辑中,在实例化非懒加载的单例 Bean 之前有一个方法 onRefresh(),留给子类去扩展,该容器就是重写这个方法创建 WebServer

    1. protected void onRefresh() {
    2. //省略....
    3. createWebServer();
    4. }
    5. private void createWebServer() {
    6. ServletWebServerFactory factory = getWebServerFactory();
    7. this.webServer = factory.getWebServer(getSelfInitializer());
    8. createWebServer.end();
    9. }

    获取 WebServer 工厂 ServletWebServerFactory,并且获取的数量不等于 1 会报错,Spring 底层有三种:

    TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory

  • 自动配置类 ServletWebServerFactoryAutoConfiguration 导入了

  • ServletWebServerFactoryConfiguration(配置类),根据条件装配判断系统中到底导入了哪个 Web 服务器的包,创建出服务器并启动

  • https://zhinan.sogou.com/guide/d316514420690.htm
    https://zhinan.sogou.com/guide/d316514420843.htm
    https://zhinan.sogou.com/guide/d316514420844.htm
    https://zhinan.sogou.com/guide/d316514420847.htm
    https://zhinan.sogou.com/guide/d316514420851.htm
    https://blog.51cto.com/weixincrm/2937542
    https://itbbs.pconline.com.cn/soft/54641412.html
    https://www.acfun.cn/a/ac29919827
    https://tieba.baidu.com/p/7416747237
    https://weibo.com/ttarticle/p/show?id=2309404650918904987994
    https://zhidao.baidu.com/question/504611436407753084.html
    https://wenwen.sogou.com/question/q935654637552733384.htm
    https://www.xiaohongshu.com/discovery/item/60d1a081000000000102e2a2

    https://zhinan.sogou.com/guide/d316514420851.htm
    https://zhinan.sogou.com/guide/d316514420847.htm
    https://zhinan.sogou.com/guide/d316514420844.htm
    https://zhinan.sogou.com/guide/d316514420844.htm
    https://zhinan.sogou.com/guide/d316514420690.htm

    https://www.meipian.cn/3o5qtuvg?share_depth=1
    https://www.im286.net/thread-24265831-1.html
    https://zhuanlan.zhihu.com/p/383220082
    https://xueqiu.com/4824316523/186894941
    https://blog.csdn.net/yunkeyi/article/details/118151701
    https://blog.51cto.com/weixincrm/2941363
    https://itbbs.pconline.com.cn/soft/54641756.html
    https://www.acfun.cn/a/ac29939481
    http://www.gzyltx.com/Articles/ArticleInfo?articleID=122&&menuID=80
    https://720yun.com/u/3e0jkpmyvn9
    https://www.processon.com/u/60d2ecd47d9c087f546def66/profile
    http://www.kuaijidao.cn/user/43802
     

  • 默认是 web-starter 导入 tomcat 包,容器中就有 TomcatServletWebServerFactory,创建出 Tomcat 服务器并启动,

    1. public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
    2. // 初始化
    3. initialize();
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/479546
推荐阅读
相关标签
  

闽ICP备14008679号