SpringBoot原理
  • Spring原理【Spring注解】,SpringMVC原理,自动配置原理,SpringBoot原理
1.SpringBoot启动过程
  1. 启动过程

  2. 创建SpringApplication—【new SpringApplication(primarySources)】

    1. 保存一些信息
    2. 判断当前的应用的类型。ClassUtils Servlet
    3. spring5中是BootstrapRegistryInitializer::去spring.factories文件中找org.springframework.boot.BootstrapRegistryInitializer【旧版是bootstrappers:初始启动引导器(List< Bootstraper>) 】
    4. 找ApplicationContextInitializer:去spring.factories找ApplicationContextInitializer
      • List<ApplicationContextInitializer<?>> initializer
    5. 找到ApplicationListener;应用监听器,作用是监听当前引用状态。去spring.factories找ApplicationListener
      • List<ApplicationListener<?>> listeners
  3. 运行SpringApplication

    1. StopWatch
    2. 记录应用的启动时间
    3. 创建引导上下文(Context环境)createBootstrapContext()
      • 获取到所有之前的bootstrappers,遍历执行initialize()方法来完成对引导启动器上下文环境设置
    4. 让当前应用进入headless模式。java.awt.headless
    5. 获取所有RunListener(运行监听器)【为了方便所有Listener进行事件感知】
      • getSpringFactoriesInstances去spring.factories找SpringApplicationRunlistener。
    6. 遍历所有SpringApplicationRunListener调用starting方法
      • 相当于通知所有感兴趣系统正在启动过程的监听器,项目此时正在starting
    7. 保存命令行参数:ApplicationArguments
    8. 准备环境prepareEnvironment()
      1. 返回或创建基础环境信息对象。StandardServletEnvironment
      2. 配置环境信息对象
        • 读取所有的配置源的配置属性值
      3. 绑定环境信息
      4. 监听器调用listener.environmentPrepared();通知所有的监听器当前环境准备完成
    9. 创建IOC容器(createApplicationContext())
      1. 根据项目类型(Servlet)创建容器;
      2. 当前会创建AnnotationConfigServletWebServerApplicationContext
    10. 准备ApplicationContext IOC容器的基本信息 prepareContext()
      1. 保存环境信息
      2. IOC容器的后置处理流程
      3. 应用初始化器,applyInitializers
        1. 遍历所有的ApplicationContextInitializer。调用initialize()方法,来对ioc容器进行初始化扩展功能
        2. 遍历所有的listener调用contextPrepared。EventPublishRunListener;通知所有的监听器contextPrepared
      4. 所有的监听器,调用contextLoaded,通知所有的监听器contextLoaded
    11. 刷新IOC容器,refreshContext
      • 创建容器中的所有组件(Spring注解)
    12. 容器刷新完成后工作?afterRefresh
    13. 所有监听器掉员工listener.started(context):通知所有监听器started事件
    14. 调用所有runners;callRunners()
      1. 获取容器中的AppllicationRunner
      2. 获取容器中的CommandLineRunner
      3. 合并所有runner并按照@Order进行排序
      4. 遍历所有合并并且排序后的Runner,调用这些runner的run()方法
    15. 如果以上有异常
      1. 调用Listener的failed
    16. 调用所有监听的running方法listeners.running(context);通知所有的监听器running
    17. running如果有问题,继续通知failer。调用所有listener的failed;通知所有的监听器failed
2.SpringBoot启动过程-创建SpringApplication【Spring应用】
  1. 调用new SpringApplication(primarySources)–【primarySources为主配置类】

  2. 初始化属性

    1. 属性名作用
      resourceLoader资源加载器
      primarySources主配置类
      webApplicationTypeweb应用类型,决定后续的IOC容器ApplicationContext
      【Servlet–》AnnotationConfigServletWebServerApplicationContext】
      BootstrapRegistryInitializer初始启动器,初始引导器
      ApplicationContextInitializerIOC容器ApplicationContext的初始化引导器
      ApplicationListener应用监听器,作用是监听当前应用状态
      mainApplicationClass主方法main的所属类,主程序类有很多,只要找到第一个包含main方法的类就可以
  3. 	@SuppressWarnings({ "unchecked", "rawtypes" })
    	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            //设置资源加载器
    		this.resourceLoader = resourceLoader;
    		Assert.notNull(primarySources, "PrimarySources must not be null");
            //设置主配置类,当前为HelloServiceSpringBootApplication
    		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
            //设置Web应用类型--当前为servlet
    		this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //获取所有的初始化启动器
    		this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
            //设置IOC容器ApplicationContext初始化引导器
    		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    		this.mainApplicationClass = deduceMainApplicationClass();
    	}
    
3.SpringBoot启动过程–运行Spring应用 【SpringApplication】
  1. 通过调用springApplication.run(args),启动SpringBoot应用

  2. 涉及的类及其作用的说明

    1. 作用获取方式
      StopWatch监听器,会调用stopWatch.start(),记录了spring应用在哪个时间启动的
      DefaultBootstrapContext默认的引导上下文,
      BootStrapRegistryInitializer引导注册初始化器从spring.factories文件中获取
      ApplicationListener监听SpringBoot启动容器过程中的事件从spring.factories文件中获取
      SpringApplicationRunListenerspring应用运行监听器适配器,这个类内部包括了所有的applicationListener,监听spring应用的事件,来做事件分发,在SpringApplicationRunListener中,
      会有一个SimpleApplicationEventMulticaster属性【应用事件分发器】,
      调用SpringApplicationRunListener的starting方法,实际是通过eventMulticaster分发事件ApplicationStartingEvent
      具体的实现类–》EventPublishingRunListener
      从spring.factories文件中获取
      ApplicationRunner回调run,自定义可以监控到listener.started()事件后的处理操作通过@Component注入IOC容器
      CommandLineRunner回调run,自定义可以监控到listener.started()事件后的处理操作通过@Component注入IOC容器
  3. 源码

    1. public ConfigurableApplicationContext run(String... args) {
          //启动监听器
         StopWatch stopWatch = new StopWatch();
         stopWatch.start();
         //创建引导上下文
         DefaultBootstrapContext bootstrapContext = createBootstrapContext();
         ConfigurableApplicationContext context = null;
          //让当前应用进入headless模式
         configureHeadlessProperty();
          //获取所有运行监听器
         SpringApplicationRunListeners listeners = getRunListeners(args);
         //遍历所有的RunListener,调用SpringApplicationRunListener的starting方法,通知所有监听器,当前项目正在starting
         listeners.starting(bootstrapContext, this.mainApplicationClass);
         try {
             //保存命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //准备运行时环境信息
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            //配置忽略的Bean信息
            configureIgnoreBeanInfo(environment);
            //打印banner
            Banner printedBanner = printBanner(environment);
            //创建IOC容器ApplicationContext
            context = createApplicationContext();
            //IOC容器ApplicationContext记录ApplicationStartup事件
            context.setApplicationStartup(this.applicationStartup);
            //准备IOC容器的信息
            prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //刷新IOC容器
            refreshContext(context);
            //容器刷新后操作
            afterRefresh(context, applicationArguments);
            //监听容器启动完成的花费时间
            stopWatch.stop();
            if (this.logStartupInfo) {
               new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            //监听器,应用启动事件
            listeners.started(context);
            //
            callRunners(context, applicationArguments);
         }
         catch (Throwable ex) {
            handleRunFailure(context, ex, listeners);
            throw new IllegalStateException(ex);
         }
      
         try {
            listeners.running(context);
         }
         catch (Throwable ex) {
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
         }
         return context;
      }
      
  4. 过程详解

    1. StopWatch stopWatch = new StopWatch();

    2. createBootstrapContext();创建引导上下文。

      1. 先创建一个DefaulteBootstrapContext,

      2. 遍历所有在创建SpringApplication时,从项目中所有META-INF/spring.factories配置的BootstrapRegistryInitializer,逐个调用BootstrapRegistryInitializer的initialize(DefaultBootstrapContext)方法,将DefaultBootstrapContext传入每个initialize()方法中

      3. private DefaultBootstrapContext createBootstrapContext() {
           DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
           this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
           return bootstrapContext;
        }
        
    3. getRunListeners(args);获取所有运行监听器,从spring.factories文件中,获取SpringApplicationRunListener.class,内置事件分发器eventMulticaster,用于做各种事件的分发

    4. private SpringApplicationRunListeners getRunListeners(String[] args) {
         Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
         return new SpringApplicationRunListeners(logger,
               getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
               this.applicationStartup);
      }
      
    5. new DefaultApplicationArguments(args); – 》保存命令行参数

    6. prepareEnvironment(listeners, bootstrapContext, applicationArguments);准备运行时环境信息

      1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
              DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
           // Create and configure the environment
           //创建基础环境信息对象
           ConfigurableEnvironment environment = getOrCreateEnvironment();
           //配置环境信息
           configureEnvironment(environment, applicationArguments.getSourceArgs());
           ConfigurationPropertySources.attach(environment);
           //通过applicationRunListener触发事件,环境信息准备完成
           listeners.environmentPrepared(bootstrapContext, environment);
           DefaultPropertiesPropertySource.moveToEnd(environment);
           Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                 "Environment prefix cannot be set via properties.");
           //绑定
           bindToSpringApplication(environment);
           if (!this.isCustomEnvironment) {
              environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
           }
           ConfigurationPropertySources.attach(environment);
           return environment;
        }
        
    7. configureIgnoreBeanInfo(environment);配置忽略的Bean信息

    8. printBanner(environment);:打印Banner

    9. createApplicationContext();:创建IOC容器ApplicationContext,根据应用类型创建IOC容器,当前创建的是AnnotationConfigServletWebServerApplicationContext【因为webapplicationType=servlet】

      1. ApplicationContextFactory DEFAULT = (webApplicationType) -> {
           try {
              switch (webApplicationType) {
              case SERVLET:
                 return new AnnotationConfigServletWebServerApplicationContext();
              case REACTIVE:
                 return new AnnotationConfigReactiveWebServerApplicationContext();
              default:
                 return new AnnotationConfigApplicationContext();
              }
           }
           catch (Exception ex) {
              throw new IllegalStateException("Unable create a default ApplicationContext instance, "
                    + "you may need a custom ApplicationContextFactory", ex);
           }
        };
        
    10. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);准备IOC容器的初始化上下文

      1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
              ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
              ApplicationArguments applicationArguments, Banner printedBanner) {
           //容器设置环境配置
           context.setEnvironment(environment);
           //应用上下文后置操作
           postProcessApplicationContext(context);
           //应用初始化器,遍历调用所有ApplicationContextInitializer的initialize()方法,对IOC容器的进行初始化扩展功能
           applyInitializers(context);
           //调用ApplicationRunListener的contextPrepared上下文准备完成事件
           listeners.contextPrepared(context);
           //调用引导信息上下文关闭事件
           bootstrapContext.close(context);
           if (this.logStartupInfo) {
              logStartupInfo(context.getParent() == null);
              logStartupProfileInfo(context);
           }
           // Add boot specific singleton beans
           //创建BeanFactory
           ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
           //将启动命令作为Bean注入BeanFactory
           beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
           if (printedBanner != null) {
              beanFactory.registerSingleton("springBootBanner", printedBanner);
           }
           //判断BeanFactory是否是DefaultListableBeanFactory,如果是调用setAllowBeanDefintionOverriding方法,允许bean定义重载
           if (beanFactory instanceof DefaultListableBeanFactory) {
              ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
           }
           //判断是否需要添加懒加载初始化Bean工厂后置处理器--LazyInitializationBeanFactoryPostProcessor
           if (this.lazyInitialization) {
              context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
           }
           // Load the sources
           Set<Object> sources = getAllSources();
           Assert.notEmpty(sources, "Sources must not be empty");
           load(context, sources.toArray(new Object[0]));
           //所有监听器调用contextLoaded,表示context加载完成
           listeners.contextLoaded(context);
        }
        
      2. 例如ServletContextApplicationContextInitializer的initialize方法设置servletContext,设置上下文属性

        • public class ServletContextApplicationContextInitializer
                implements ApplicationContextInitializer<ConfigurableWebApplicationContext>, Ordered {
          
          
             @Override
             public void initialize(ConfigurableWebApplicationContext applicationContext) {
                applicationContext.setServletContext(this.servletContext);
                if (this.addApplicationContextAttribute) {
                   this.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
                         applicationContext);
                }
          
             }
          
          }
          
    11. refreshContext(context);刷新IOC容器,

      1. 其中onRefresh()方法被子类AnnotationConfigServletWebServerApplicationContext重写
      2. 在AnnotationConfigServletWebServerApplicationContext的onRefresh()方法中,会调用createWebServer()方法,来创建并启动WebServer
      3. 具体是通过从容器中获取到WebServerFactory,调用getWebServer()方法获取到WebServer,并启动
    12. afterRefresh(context, applicationArguments);刷新容器后操作

    13. listeners.started(context);调用监听器,触发应用已启动事件

    14. callRunners(context, applicationArguments);调用所有的runners,获取容器中的ApplicationRunner和CommandRunner

    15. private void callRunners(ApplicationContext context, ApplicationArguments args) {
         List<Object> runners = new ArrayList<>();
         runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
         runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
         AnnotationAwareOrderComparator.sort(runners);
         for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
               callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
               callRunner((CommandLineRunner) runner, args);
            }
         }
      }
      
    16. handleRunFailure(context, ex, listeners); 如果有异常,调用监听器的failed事件,进行分发。然后进入异常日志记录,抛出异常

      1. private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
              SpringApplicationRunListeners listeners) {
           try {
              try {
                 handleExitCode(context, exception);
                 if (listeners != null) {
                    listeners.failed(context, exception);
                 }
              }
              finally {
                 reportFailure(getExceptionReporters(context), exception);
                 if (context != null) {
                    context.close();
                 }
              }
           }
           catch (Exception ex) {
              logger.warn("Unable to close ApplicationContext", ex);
           }
           ReflectionUtils.rethrowRuntimeException(exception);
        }
        
    17. listener.running(context):调用触发所有监听器的running方法,通知监听器应用进入running方法,running方法在上述容器创建和初始化之后,如果在容器创建和初始化过程中出现异常,不影响listeners.running(),而listener.running出错的话,不会调用listener的failed()方法,会直接退出

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐