Springboot启动流程分析

目录

  1. 先简单介绍一些SpringBoot 组件
  2. 介绍启动流程

参考资料

@SpringBootConfiguration的介绍

首先介绍以下@SpringbootConfiguration的作用

  1. 源码内含@Configuration ,也就是用@SpringbootConfiguration 的类就可以当配置类,如main方法也可以作为配置类 【可以参考 注解@SpringbootConfiguration 的源码】
  2. @SpringbootConfiguration会将当前类内声明的一个或多个用@Bean注解标记的方法的实例放到入到spring容器IOC中,并且实例名就是方法名。

接下来 通过springboot的启动,我们用代码的运行结果来说明上面的情况

  • 代码1 是Springboot启动类 也充当配置类

    @SpringBootApplication
    public class SpringbootdemoApplication {
      public static void main(String[] args) {
          //在这里标明以下SpringApplication.run方法返回的是spring的IOC容器
          //ConfigurableApplicationContext 跟ClassPathXmlApplicationContext都是ApplicationContext实现类
          ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootdemoApplication.class, args);
          System.out.println(applicationContext.getBean("getPerson"));
          System.out.println(applicationContext.getBean("student"));
      }
    
      @Bean
      public Person getPerson() {
          return new Person();
      }
    
      public static class Person { } //Person类
    }
  • 代码2 自己写的配置类

    @Configuration   //同样Configuration也可以改为SpringBootApplication
    public class MyConfig {
      @Bean
      public Student student(){
          return new Student();
      }
      public static class Student{}//Student类
    }
  • 效果 两个类都放到了IOC容器中

    图片说明

springboot启动类的run真正的是

  • 代码
      SpringApplication.run(SpringbootdemoApplication.class, args);
    ||   进入run方法
    \/  
      public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
          return run(new Class[]{primarySource}, args);
      }
    ||  再次进入run方法
    \/
      public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
          return (new SpringApplication(primarySources)).run(args);
      }
    ||
    \/   再次进入的run方法是下面的ConfigurableApplicationContext 请继续看

这时候可以知道springboot基本的启动流程

  1. 创建new SpringApplication

  2. 调用run方法 .run

    也就是运行下面这一堆 这一堆也是springboot运行的底层启动流程代码 后面会更详细介绍

     public ConfigurableApplicationContext run(String... args) {
         StopWatch stopWatch = new StopWatch();
         stopWatch.start();//里面的代码实际就是System.currentTimeMillis();用来计时启动事件
         ConfigurableApplicationContext context = null; //IOC容器
         //exceptionReporters  异常的报告器
         Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
         this.configureHeadlessProperty();
         SpringApplicationRunListeners listeners = this.getRunListeners(args);
         listeners.starting();
    
         Collection exceptionReporters;
         try {
             ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
             ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
             this.configureIgnoreBeanInfo(environment);
    //Banner 也就是spring的广告图 我们可以换成其他一些好玩的
             Banner printedBanner = this.printBanner(environment);
             context = this.createApplicationContext();
             exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
             this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
             this.refreshContext(context);
             this.afterRefresh(context, applicationArguments);
             stopWatch.stop();//跟上面的start对应 计时器
             if (this.logStartupInfo) {
                 (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
             }
    
             listeners.started(context);
             this.callRunners(context, applicationArguments);
         } catch (Throwable var10) {
             this.handleRunFailure(context, var10, exceptionReporters, listeners);
             throw new IllegalStateException(var10);
         }
    
         try {
             listeners.running(context);
             return context;
         } catch (Throwable var9) {
             this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
             throw new IllegalStateException(var9);
         }
     }

SpringApplication的初始化过程

  • 代码 做初始化

    //构造函数
      public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 
          this.sources = new LinkedHashSet();
          this.bannerMode = Mode.CONSOLE;
          this.logStartupInfo = true;
          this.addCommandLineProperties = true;
          this.addConversionService = true;
          this.headless = true;
          this.registerShutdownHook = true;
          this.additionalProfiles = new HashSet();
          this.isCustomEnvironment = false;
          this.lazyInitialization = false;
          this.resourceLoader = resourceLoader;
          Assert.notNull(primarySources, "PrimarySources must not be null");
    //重点
    // primarySources 接收启动器的args参数
          this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
          this.webApplicationType = WebApplicationType.deduceFromClasspath();
          this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
          this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
          this.mainApplicationClass = this.deduceMainApplicationClass();
      }
  • WebApplicationType : 一般是得到SERVLET WebApplicationType应用类型
    可以干嘛呢? 我们可以通过配置来设置是否使用Springboot内置的tomcat
    如:
    web-application-type:none 为none时 需要配置外部Tomcat执行
    为servlet时 用的是自身的Tomcat

      static WebApplicationType deduceFromClasspath() {
    //下面是判断有没有对应的类 响应式编程需要webflux包 暂时没有
    //isPresent的底层是用反射来生成传入的字符串  然后看看那些类必须有 那些类不能有
          if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
              return REACTIVE;//reactive : spring5的新特性 代表是否用响应式编程
          } else {
             //到了else 说明含有DispatcherServlet
              String[] var0 = SERVLET_INDICATOR_CLASSES;//SERVLET_INDICATOR_CLASSES的值看下面
    // private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};   查找又没有后面的类 有的√
    //找出DispatchServlet
              int var1 = var0.length;
    //遍历我们需要的类SERVLET_INDICATOR_CLASSES是否存在 不存在return NONE 
              for(int var2 = 0; var2 < var1; ++var2) {
                  String className = var0[var2];
                  if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                      return NONE;
                  }
              }
              return SERVLET;
          }
      }
  • setInitializers 对容器一些初始化配置

    运行  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
    其中getSpringFactoriesInstances的底层是 SpringFactoriesLoader 【去找META-INF/spring.factories】
    this.getSpringFactoriesInstances(ApplicationContextInitializer.class)中的
    
    ApplicationContextInitializer在以下找
    META-INF/spring.factories文件对应的内容为
    # Application Context Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
    org.springframework.boot.context.ContextIdApplicationContextInitializer,\
    org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
    org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
    org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
    
    //在springApplication中有SpringFactoriesLoader.loadFactoryNames 
    //利用其去.properties文件中进行查找 【基本的配置文件♥】
      private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
          ClassLoader classLoader = this.getClassLoader();
          Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
          List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
          AnnotationAwareOrderComparator.sort(instances);
          return instances;
      }
    ||
    \/   SpringFactoriesLoader.loadFactoryNames(type, classLoader)的具体方法
      public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
      public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
          String factoryTypeName = factoryType.getName();
          return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
      }
  • setListeners:

  • mainApplicationClass:启动类

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 {
}

注解包装了SpringBootConfiguration【包含了Configuration 类似xml】、EnableAutoConfiguration、ComponentScan【default "*/.class" 当前文件路径会自动被扫描】

  • EnableAutoConfiguration的作用【auto配置文件 ♥】 -->DispatcherServlet(springmvc)
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {}
    遍历所有的Auto配置文件里面的组件(如果一些没法添加 后来就没有加入IOC中)
    图片说明

springboot如何加载tomcat 和springmvc

tomcat

  • 从配置取出的类 已经是加载到了ioc中 该类通过ctrl+alt+shift+N找的 会加到springboot里面
    含有三个服务器的配置文件
    @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
          ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
          ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
          ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
    public class ServletWebServerFactoryAutoConfiguration {
      @Bean
      public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
          return new ServletWebServerFactoryCustomizer(serverProperties);
      }//注意后面的serverProperties
    }
    ctrl + K 得知是开启tomcat
    图片说明
    下面的类会读取自己写的yaml配置
    @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
    public class ServerProperties {
      /**
       * Server HTTP port.
       */
      private Integer port;
    }
    在tomcat工厂中是实现了new Tomcat(); 后面设置tomcat 然后启动mvc
    图片说明

DispatcherServletAutoConfiguration

  • 配置

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)//DispatcherServlet注入ioc中
    @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
    public class DispatcherServletAutoConfiguration {
    
      public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
      public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
    
      @Configuration(proxyBeanMethods = false)
      @Conditional(DefaultDispatcherServletCondition.class)
      @ConditionalOnClass(ServletRegistration.class)
      @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
      protected static class DispatcherServletConfiguration {
    
          @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
          public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
          ...
              return dispatcherServlet;
          }
  • 自定义的配置

    @ConfigurationProperties(prefix = "spring.mvc")
    public class WebMvcProperties {
       private Locale locale;
    }

启动流程

SpringApplication -> run - > ConfigurableApplicationContext
博客运行流程
代码同上面的

下面也是SpringApplication的run方法
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();//实际就是System.currentTimeMillis()
        ConfigurableApplicationContext context = null; //IOC容器
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();//记录错误日志
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
//Banner 也就是spring的广告图 我们可以换成其他一些好玩的
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();//跟上面的start对应 计时器
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • 自定义外部扩展文件
    利用底层的源代码 将my.properties放入springboot

总结启动流程

  1. 创建springApplication 对象 new SpringApplication ,Springboot容器初始化操作

  2. 获取当前应用启动类型 原理:判断classpath是否有加载我们的servlet类 返回servlet web启动方式

       this.webApplicationType = WebApplicationType.deduceFromClasspath();
    类型:REACTIVE NONE SERVLET
  3. setInitializers:读取SpringBoot包下面的META-INF/spring.factories 获取对应的ApplicationContextInitializer装配到集合中

  4. setListeners :读取SpringBoot包下面的META-INF/spring.factories 获取对应的ApplicationContextListener装配到集合中

  5. mainApplicationClass获取当前运行的主函数

  6. 调用springApplication的 run方法 也就是上面的方法ConfigurableApplicationContext run 实现启动

  7. StopWatch stopWatch = new StopWatch();记录我们springboot项目启动时间

  8. 运行下面的代码 getRunListeners读取我们的META-INF/spring.factories文件 如SpringApplicationRunListener

    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    ||
    \/
     private SpringApplicationRunListeners getRunListeners(String[] args) {
         Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
         return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
     }
    ||
    \/
    getSpringFactoriesInstances :读取spring.factories文件
    ||
    \/
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
     private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
         ClassLoader classLoader = this.getClassLoader();
         Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
         List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
         AnnotationAwareOrderComparator.sort(instances);
         return instances;
     }
    上面的代码经过核对跟上面获取 setInitializers  setListeners 一致
    但是获取到的结果不应用 找的方式相同 上面返回的SpringApplicationRunListener类
    
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));   
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    其中的SpringFactoriesLoader到"META-INF/spring.factories"下找配置文件的内容
    
    找到了 spring.factories下的
    org.springframework.boot.SpringApplicationRunListener=\
    org.springframework.boot.context.event.EventPublishingRunListener

    图片说明
    EventPublishingRunListener:作用是给我们springboot配置文件(application.yaml...)进行赋值 参数文件配置到容器中

  9. listeners.starting(); 循环调用start方法

    void starting() { //所有的***进行启动
        Iterator var1 = this.listeners.iterator();
        while(var1.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
            listener.starting();
        }
    }
    
    在EventPublishingRunListener的start方法
    public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

    先插入讲一个运用场景
    图片说明
    自定义一个类SpringApplicationRunListener

    文件路径--->main\resources\META-INF\spring.factories:
    org.springframework.boot.SpringApplicationRunListener=\
    com.project.springbootdemo.MySpringBootApplicationRunListener
    
    //仿造 EventPublishingRunListener来编写代码
    public class MySpringBootApplicationRunListener implements SpringApplicationRunListener {
    //application、args、MySpringBootApplicationRunListener:必备的代码
    private final SpringApplication application;
    private final String[] args;
    
    public MySpringBootApplicationRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
    }
    
    @Override
    public void starting() {
        System.out.println("---->>>starting");
    }
    
    //配置文件读取到程序中,需要自己将本地文件读取到程序中,然后再放入spring容器
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {//environment是springboot提供的
        System.out.println("---->>>environmentPrepared");
        Properties properties = new Properties();
        try {
            //读取我们的配置文件
            properties.load(getClass().getClassLoader().getResourceAsStream("my.properties"));
            //读取名称
            PropertySource propertySource = new PropertiesPropertySource("person.name", properties);
            //将资源添加到Springboot项目中
            //取出environment的getPropertySources
            MutablePropertySources propertySources = environment.getPropertySources();
            // 通过该api接口可以将配置文件读取到springboot项目中
            propertySources.addLast(propertySource);
            System.out.println(propertySources.size());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("---->>>contextPrepared");
    }
    
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("---->>>contextLoaded");
    }
    
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("---->>>started");
    }
    }

    记载成功
    图片说明
    读取成功

    @RestController
    public class TestController {
    @Value("${person.name}")  //从environment里面取
    private String value;
    @RequestMapping("/hello")
    public String hello(Map<String,Object>map){
        return value;
    }
    }

    图片说明

  10. 参数赋值

    ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
    ||
    \/
    private ConfigurableEnvironment  prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { 
    // 运行***environmentPrepared 读取配置文件到springboot容器中 参考我们写的MySpringBootApplicationRunListener 
      listeners.environmentPrepared((ConfigurableEnvironment)environment);
    }
    ||
    \/
    void environmentPrepared(ConfigurableEnvironment environment) {
        Iterator var2 = this.listeners.iterator();
        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
    //下面的方法是重点  我们重点研究EventPublishingRunListener
            listener.environmentPrepared(environment);
        }
    }
    ||
    \/  进入EventPublishingRunListener
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }
    ||
    \/
    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }
    ||
    \/
    public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
        Executor executor = this.getTaskExecutor();
        Iterator var5 = this.getApplicationListeners(event, type).iterator();
        while(var5.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var5.next();
            if (executor != null) {
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
    运行------>     this.invokeListener(listener, event);
            }
        }
    }
    ||
    \/
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
    运行----->          this.doInvokeListener(listener, event);
        }
    }
    ||
    \/
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
    运行 --->           listener.onApplicationEvent(event);//有很多事件 
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
                throw var6;
            }
    
            Log logger = LogFactory.getLog(this.getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, var6);
            }
        }
    }
    listener.onApplicationEvent(event);EventPublishingRunListener找的是ConfigFileApplicationListener 
    去默认配置的路径找 "classpath:/,classpath:/config/,file:./,file:./config/";
    ||
    \/
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            运行---->this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
        }
    
        if (event instanceof ApplicationPreparedEvent) {
            this.onApplicationPreparedEvent(event);
        }
    }
    ||
    \/
    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();
        postProcessors.add(this);
        AnnotationAwareOrderComparator.sort(postProcessors);
        Iterator var3 = postProcessors.iterator();
    
        while(var3.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
            运行--->postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());//找到的是ConfigFileApplicationListener***
        }
    }
    ||
    \/
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        this.addPropertySources(environment, application.getResourceLoader());
    }
    ||
    \/
    protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
        RandomValuePropertySource.addToEnvironment(environment);
        (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();    //Loader类读取一些配置文件 重点看load方法
    }
    ||
    \/
    public void load(){}
    ||
    \/
        private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            this.getSearchLocations().forEach((location) -> {
                boolean isFolder = location.endsWith("/");
                Set<String> names = isFolder ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES;
    for循环            names.forEach((name) -> {
    -->                  this.load(location, name, profile, filterFactory, consumer);
                });
            });
        }
    ||
    \/   所有的配置路径会遍历一遍 除非找到目标文件
        private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            if (!StringUtils.hasText(name)) {
                Iterator var13 = this.propertySourceLoaders.iterator();
    
                PropertySourceLoader loader;
                do {
                    if (!var13.hasNext()) {
                        throw new IllegalStateException("File extension of config file location '" + location + "' is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/'");
                    }
    
                    loader = (PropertySourceLoader)var13.next();
                } while(!this.canLoadFileExtension(loader, location));
    
                this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
            } else {
                Set<String> processed = new HashSet();
                Iterator var7 = this.propertySourceLoaders.iterator();
    
    // PropertySourceLoader 分析得到他的继承类有两个properties yaml 其中子类实现的文件后缀有 properties xml yaml yml
                while(var7.hasNext()) {
                    PropertySourceLoader loaderx = (PropertySourceLoader)var7.next(); 
                    String[] var9 = loaderx.getFileExtensions();
                    int var10 = var9.length;
    
                    for(int var11 = 0; var11 < var10; ++var11) {
                        String fileExtension = var9[var11];
                        if (processed.add(fileExtension)) {
                            this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer);
                        }
                    }
                }
    
            }
        }
    ||
    \/
        private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) {
            this.load(loader, prefix + fileExtension, profile, profileFilter, consumer);
    
    }
    ||
    \/
        private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) {
            try {
                Resource resource = this.resourceLoader.getResource(location);
               else {
                        String name = "applicationConfig: [" + location + "]";
    
    ---->List<ConfigFileApplicationListener.Document> documents = this.loadDocuments(loader, name, resource);
                        if (CollectionUtils.isEmpty(documents)) {
                            if (this.logger.isTraceEnabled()) {
                                StringBuilder description = this.getDescription("Skipped unloaded config ", location, resource, profile);
                                this.logger.trace(description);
                            }
    
                        }
    ...
    }
    ||
    \/ 读取加载成功后 通过  this.addLoadedPropertySources();将文件记载到springboot中 如environment
        private void addLoadedPropertySources() {
            MutablePropertySources destination = this.environment.getPropertySources();
            List<MutablePropertySources> loaded = new ArrayList(this.loaded.values());
            Collections.reverse(loaded);
            String lastAdded = null;
            Set<String> added = new HashSet();
            Iterator var5 = loaded.iterator();
    ....
    }

    图片说明

    去默认配置文件路径下找 file【直接编译前的配置文件】 classpath【读取编译后的配置文件】 默认读取application
    图片说明
    PropertySourceLoader 分析得到他的实现类有两个properties yaml 其中子类实现的文件后缀有 properties xml yaml yml每一种都会读取以下
    最后在对应的路径下找到了 然后在PropertySourceLoader 的实现类中解析
    图片说明

  11. 读取会覆盖 Order制定优先级(Event*** )
    读取顺序properties xml yml yaml

  12. 打印springboot Banner图

  13. context = this.createApplicationContext(); 初始化AnnotationConfigServletWebServerApplicationContext(IOC)

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
              --->      contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
    
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }
  14. 先做一些的提前准备 然后执行this.refreshContext(context);刷新上下文

           this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
           this.refreshContext(context);
    ||
    \/
    private void refreshContext(ConfigurableApplicationContext context) {
       this.refresh(context);
       if (this.registerShutdownHook) {
           try {
               context.registerShutdownHook();
           } catch (AccessControlException var3) {
           }
       }
    }
    ||
    \/
    protected void refresh(ApplicationContext applicationContext) {
       Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
       ((AbstractApplicationContext)applicationContext).refresh();
    -->选择到ServletWebServerApplicationContext 
    }
    ||
    \/  
    public final void refresh() throws BeansException, IllegalStateException {
       try {
           super.refresh();  springioc的创建方法
       } catch (RuntimeException var2) {
           this.stopAndReleaseWebServer();
           throw var2;
       }
    }
    ||
    \/ super.refresh 中有一个            
    this.OnRefresh()
    ||
    \/
    this.createWebServer();
    ||
    \/
    private void createWebServer() {
       WebServer webServer = this.webServer;
       ServletContext servletContext = this.getServletContext();
       if (webServer == null && servletContext == null) {
           ServletWebServerFactory factory = this.getWebServerFactory();
    //获得tomcat
           this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
       }
    }
  15. 创建tomcat

    @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
    
    ---->ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
    public class ServletWebServerFactoryAutoConfiguration {
    ...
    }
    ||
    \/
    static class EmbeddedTomcat {
    
        @Bean
    --->    TomcatServletWebServerFactory tomcatServletWebServerFactory(
                ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
                ObjectProvider<TomcatContextCustomizer> contextCustomizers,
                ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
            factory.getTomcatConnectorCustomizers()
                    .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatContextCustomizers()
                    .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatProtocolHandlerCustomizers()
                    .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
            return factory;
        }
    ||
    \/
    TomcatServletWebServerFactory 
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
    }

    图片说明

  16. 开始加载springmvc

    @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)
    @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
    public class DispatcherServletAutoConfiguration {
    @Configuration(proxyBeanMethods = false)
    @Conditional(DefaultDispatcherServletCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
    protected static class DispatcherServletConfiguration {
    
    --->    @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
            dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
            dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
            dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
            dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
            return dispatcherServlet;
        }
    }
  1. 定义afterRefresh 是一个空方法
    让用户自定义编写
    protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    }
  1. 调用started 告诉别人***启动成功
  2. listener.running()
全部评论

相关推荐

11-04 14:10
东南大学 Java
_可乐多加冰_:去市公司包卖卡的
点赞 评论 收藏
分享
点赞 1 评论
分享
牛客网
牛客企业服务