• springboot启动原理解析


    springboot核心原理:
      1.基于springmvc无配置文件完全注解化 + 内置web容器实现springboot框架。main函数方式的启动
      2.通过maven快速整合第三方框架
    springboot两个核心
      内置的Tomcat(ServletWebServerFactoryAutoConfiguration)
      dispatcherServlet(DispathcerServletAutoConfiguration)
    springboot启动流程
      1.创建SpringApplication对象
      2.调用SpringApplication.run()方法启动项目,同时返回当前容器的上下文
    流程:
      1.判断当前应用的启动类型(webApplicationType):servlet?reactive?none?
      2.加载spring.factories中所有的ApplicationContextInitializer的实现类,存到集合中
      3.加载spring.factories中所有的ApplicationListener的实现类,存到集合中
      4.推断当前项目的启动main函数:在方法中抛出一个运行时异常,获取异常栈信息中main方法对应的className
    启动:
      1.记录当前项目的启动耗时
      2.加载spring.factories文件中SpringApplicationRunListener的实现类EventPublishingRunListener(在后面,spring会通过多事件派发器来通知所有的事件监听器)
      3.发布starting事件
      4.发布prepareEnvironment事件:在这里,会获取到spring的配置文件,并按照优先级进行覆盖;该方法主要是完成了将application.properties配置文件配置的内容赋值到spring容器中的作用(优先级的覆盖),最后,会调用MutablePropertySources.addLast()方法
      5.根据webApplicationType来创建上下文环境(ConfigurableApplicationContext)
      6.刷新容器:在刷新容器中,会调用子类的onRefresh()方法,早onRefresh()方法中初始化dispatcherServlet、启动Tomcat容器
      8.发布started事件和running事件 
     
     1 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
     2         this.resourceLoader = resourceLoader;
     3         Assert.notNull(primarySources, "PrimarySources must not be null");
     4         this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
     5         //判断当前应用是什么哪种类型的 none/servlet/reaction
     6         this.webApplicationType = WebApplicationType.deduceFromClasspath();
     7         //从META-INF/spring.factories中读取ApplicationContextInitializer的实现类,放到集合中
     8         setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
     9         //从META-INF/spring.factories中读取ApplicationListener的实现类,放到集合中
    10         setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    11         //获取到当前应用的启动函数 main方法
    12         this.mainApplicationClass = deduceMainApplicationClass();
    13     }
     1 public ConfigurableApplicationContext run(String... args) {
     2     //获取时间戳,用来计算启动时间
     3     StopWatch stopWatch = new StopWatch();
     4     stopWatch.start();
     5     ConfigurableApplicationContext context = null;
     6     Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     7     configureHeadlessProperty();
     8     /**
     9      * 获取spring.factories文件中SpringApplicationRunListener的实现类
    10      * 在调用starting的时候,会通过multicastEvent(多事件派发器)发送事件消息,会通知所有的事件监听器,让监听器判断是否对当前发布的事件感兴趣,如果感兴趣,就调用当前监听器的onApplicationEvent()方法
    11      * 那是如何判断当前监听器是否对多事件派发器发送的事件感兴趣呢?
    12      * supportsSourceType
    13      * 和supportsEventType这两个方法
    14      */
    15     SpringApplicationRunListeners listeners = getRunListeners(args);
    16     listeners.starting();
    17     try {
    18         ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    19         //发布prepareEnviroment事件,在这个事件中,org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent会完成spring
    20         //boot配置文件优先级的读取和覆盖
    21         ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    22         configureIgnoreBeanInfo(environment);
    23         Banner printedBanner = printBanner(environment);
    24         //初始化容器上下文,根据webApplicationType类型来判断
    25         context = createApplicationContext();
    26         exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    27                 new Class[] { ConfigurableApplicationContext.class }, context);
    28         prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    29         //刷新spring容器,在这个方法里面完成了Tomcat的初始化和dispatcherServlet的初始化
    30         refreshContext(context);
    31         afterRefresh(context, applicationArguments);
    32         stopWatch.stop();
    33         if (this.logStartupInfo) {
    34             new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    35         }
    36         listeners.started(context);
    37         callRunners(context, applicationArguments);
    38     }
    39     catch (Throwable ex) {
    40         handleRunFailure(context, ex, exceptionReporters, listeners);
    41         throw new IllegalStateException(ex);
    42     }
    43 
    44     try {
    45         listeners.running(context);
    46     }
    47     catch (Throwable ex) {
    48         handleRunFailure(context, ex, exceptionReporters, null);
    49         throw new IllegalStateException(ex);
    50     }
    51     return context;
    52 }

    这个是springboot启动流程的源码,其中有两个点是比较重要的:

      1.prepareEnviroment事件的发布(springboot配置文件的解析)

      2.刷新spring容器,完成Tomcat的初始化和dispatcherServlet的初始化

  • 相关阅读:
    sqlserver FOR XML查询参数RAW的实例
    Dinky使用——mysql2clickhouse
    7、Canal实现MySQL到ES实时同步2
    加一
    极大极小游戏
    Dinky 0.6.5安装部署
    多数元素
    Dinky的使用——hbase2mysql
    packetbeat配置
    大数据分析与展示
  • 原文地址:https://www.cnblogs.com/mpyn/p/12044014.html
Copyright © 2020-2023  润新知