• springboot启动流程分析


    1.从应用程序启动入口开始追踪代码:

    SpringApplication.run(SpringbootDemoApplication.class, args);

    2.进入SpringApplication类的构造方法:

    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. this.webApplicationType = WebApplicationType.deduceFromClasspath();
    6. this.bootstrapRegistryInitializers = new ArrayList<>(
    7. getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    8. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    9. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    10. this.mainApplicationClass = deduceMainApplicationClass();
    11. }

    这个步骤做了以下几件事:

    a.初始化资源加载器,但是从上下文可以看出是null

    b.设置主资源类,即第一步传过来的SpringbootDemoApplication类

    c.推断webApplicationType的类型:WebApplicationType.SERVLET

    d.设置bootstrapRegistryInitializers数据,通过SpringFactoriesLoader从META-INF/spring.factories目录加载key为BootstrapRegistryInitializer的数据并初始化

    e.设置initializers,通过SpringFactoriesLoader从上下文中所以jar根目录META-INF/spring.factories目录加载key为ApplicationContextInitializer的数据并初始化

    f.设置listeners,通过SpringFactoriesLoader从上下文中所以jar根目录META-INF/spring.factories目录加载key为ApplicationListener的数据并初始化

    j.推断主应用类,即SpringbootDemoApplication类

    3.接着继续进入SpringApplication类的run方法中,如下代码:

    1. public ConfigurableApplicationContext run(String... args) {
    2. long startTime = System.nanoTime();
    3. // a.创建一个springboot上下文对象
    4. DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    5. ConfigurableApplicationContext context = null;
    6. configureHeadlessProperty();
    7. // b.获取并启动监听的listeners
    8. SpringApplicationRunListeners listeners = getRunListeners(args);
    9. listeners.starting(bootstrapContext, this.mainApplicationClass);
    10. try {
    11. // c.初始化应用环境
    12. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    13. ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
    14. configureIgnoreBeanInfo(environment);
    15. // 打印启动banner数据
    16. Banner printedBanner = printBanner(environment);
    17. // d.初始化应用上下文
    18. context = createApplicationContext();
    19. context.setApplicationStartup(this.applicationStartup);
    20. // e.刷新应用上下文前的准备工作
    21. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
    22. // f.刷新应用上下文
    23. refreshContext(context);
    24. // j.刷新应用上下文之后的扩展功能
    25. afterRefresh(context, applicationArguments);
    26. Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    27. if (this.logStartupInfo) {
    28. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
    29. }
    30. listeners.started(context, timeTakenToStartup);
    31. // h.调用ApplicationRunner和CommandLineRunner的run方法
    32. callRunners(context, applicationArguments);
    33. }
    34. catch (Throwable ex) {
    35. handleRunFailure(context, ex, listeners);
    36. throw new IllegalStateException(ex);
    37. }
    38. try {
    39. Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
    40. listeners.ready(context, timeTakenToReady);
    41. }
    42. catch (Throwable ex) {
    43. handleRunFailure(context, ex, null);
    44. throw new IllegalStateException(ex);
    45. }
    46. return context;
    47. }

    接下来具体解释一下,每一步的细节:

    a.创建springboot上下文对象:创建一个类型为DefaultBootstrapContext的上下文对象,并且将第二步获取过来的bootstrapRegistryInitializers执行初始化操作,执行initialize方法

    1. private DefaultBootstrapContext createBootstrapContext() {
    2. DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    3. this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
    4. return bootstrapContext;
    5. }
    BootstrapRegistryInitializer接口类:
    1. @FunctionalInterface
    2. public interface BootstrapRegistryInitializer {
    3. /**
    4. * Initialize the given {@link BootstrapRegistry} with any required registrations.
    5. * @param registry the registry to initialize
    6. */
    7. void initialize(BootstrapRegistry registry);
    8. }

    可以自行实现该接口并做某些初始化作用,这个初始化的时机比较早。

    b.获取并启动监听的listeners:获取并实例化所有类型为SpringApplicationRunListener的listener

    1. private SpringApplicationRunListeners getRunListeners(String[] args) {
    2. Class[] types = new Class[] { SpringApplication.class, String[].class };
    3. return new SpringApplicationRunListeners(logger,
    4. getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
    5. this.applicationStartup);
    6. }

    启动listener

    1. void starting(ConfigurableBootstrapContext bootstrapContext, Class mainApplicationClass) {
    2. doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
    3. (step) -> {
    4. if (mainApplicationClass != null) {
    5. step.tag("mainApplicationClass", mainApplicationClass.getName());
    6. }
    7. });
    8. }

    进入org.springframework.boot.context.event.EventPublishingRunListener#starting方法中(说明:EventPublishingRunListener这个runlistener是通过反射初始化的,通过getRunListeners反射调用的是EventPublishingRunListener(SpringApplication application, String[] args) 这个构造方法,有兴趣可以看看,里面初始化了多播器:initialMulticaster和当前应用对象:application):发布了一个ApplicationStartingEvent事件对象

    1. @Override
    2. public void starting(ConfigurableBootstrapContext bootstrapContext) {
    3. this.initialMulticaster
    4. .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
    5. }

    继续追踪到org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)方法:

    1. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    2. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    3. Executor executor = getTaskExecutor();
    4. for (ApplicationListener listener : getApplicationListeners(event, type)) {
    5. if (executor != null) {
    6. executor.execute(() -> invokeListener(listener, event));
    7. }
    8. else {
    9. invokeListener(listener, event);
    10. }
    11. }
    12. }

    继续追到org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener:

    1. private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    2. try {
    3. listener.onApplicationEvent(event);
    4. }
    5. catch (ClassCastException ex) {
    6. // 省略部分代码...
    7. }
    8. }

    最终执行各个listener的onApplicationEvent方法。

    springboot中所有的事件发布都是由org.springframework.boot.context.event.EventPublishingRunListener这个类来发布完成的,它会在容器初始化的各个阶段发布各种不同的事件,关注了这个事件的监听器就能接受到,然后执行对应的方法。

    c.初始化应用环境,代码如下:

    1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
    2. ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    3. ApplicationArguments applicationArguments, Banner printedBanner) {
    4. context.setEnvironment(environment);
    5. postProcessApplicationContext(context);
    6. // 执行第二步获取的initializers方法
    7. applyInitializers(context);
    8. // 发布一个ApplicationContextInitializedEvent类型的事件,告诉listener准备监听
    9. listeners.contextPrepared(context);
    10. bootstrapContext.close(context);
    11. if (this.logStartupInfo) {
    12. logStartupInfo(context.getParent() == null);
    13. logStartupProfileInfo(context);
    14. }
    15. // Add boot specific singleton beans
    16. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    17. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    18. if (printedBanner != null) {
    19. beanFactory.registerSingleton("springBootBanner", printedBanner);
    20. }
    21. if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
    22. ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
    23. if (beanFactory instanceof DefaultListableBeanFactory) {
    24. ((DefaultListableBeanFactory) beanFactory)
    25. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    26. }
    27. }
    28. if (this.lazyInitialization) {
    29. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    30. }
    31. context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    32. // Load the sources
    33. Set sources = getAllSources();
    34. Assert.notEmpty(sources, "Sources must not be empty");
    35. load(context, sources.toArray(new Object[0]));
    36. listeners.contextLoaded(context);
    37. }
    38. d.初始化应用上下文:

      1. context = createApplicationContext();
      2. context.setApplicationStartup(this.applicationStartup);

      e.刷新应用上下文前的准备工作(跟spring无缝对接起来)org.springframework.context.support.AbstractApplicationContext#refresh:

      1. public void refresh() throws BeansException, IllegalStateException {
      2. synchronized (this.startupShutdownMonitor) {
      3. StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      4. // Prepare this context for refreshing.
      5. prepareRefresh();
      6. // Tell the subclass to refresh the internal bean factory.
      7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      8. // Prepare the bean factory for use in this context.
      9. prepareBeanFactory(beanFactory);
      10. try {
      11. // Allows post-processing of the bean factory in context subclasses.
      12. postProcessBeanFactory(beanFactory);
      13. StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
      14. // Invoke factory processors registered as beans in the context.
      15. invokeBeanFactoryPostProcessors(beanFactory);
      16. // Register bean processors that intercept bean creation.
      17. registerBeanPostProcessors(beanFactory);
      18. beanPostProcess.end();
      19. // Initialize message source for this context.
      20. initMessageSource();
      21. // Initialize event multicaster for this context.
      22. initApplicationEventMulticaster();
      23. // Initialize other special beans in specific context subclasses.
      24. onRefresh();
      25. // Check for listener beans and register them.
      26. registerListeners();
      27. // Instantiate all remaining (non-lazy-init) singletons.
      28. finishBeanFactoryInitialization(beanFactory);
      29. // Last step: publish corresponding event.
      30. finishRefresh();
      31. }
      32. catch (BeansException ex) {
      33. // 省略代码...
      34. }
      35. finally {
      36. // Reset common introspection caches in Spring's core, since we
      37. // might not ever need metadata for singleton beans anymore...
      38. resetCommonCaches();
      39. contextRefresh.end();
      40. }
      41. }
      42. }

      h.调用ApplicationRunner和CommandLineRunner的run方法,它的执行时机是容器启动完成的时候,实现对应的接口即可:

      1. private void callRunners(ApplicationContext context, ApplicationArguments args) {
      2. List runners = new ArrayList<>();
      3. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
      4. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
      5. AnnotationAwareOrderComparator.sort(runners);
      6. for (Object runner : new LinkedHashSet<>(runners)) {
      7. if (runner instanceof ApplicationRunner) {
      8. callRunner((ApplicationRunner) runner, args);
      9. }
      10. if (runner instanceof CommandLineRunner) {
      11. callRunner((CommandLineRunner) runner, args);
      12. }
      13. }
      14. }
      15. 相关阅读:
        STM32CubeMX教程11 RTC 实时时钟 - 入侵检测和时间戳
        whois信息收集&企业备案信息
        Python-Websocket的介绍及使用方法
        ES6 Class(类) 总结(九)
        两个宝藏|关于我在github上冲浪时的一个小技巧。
        卧槽Winform也可以这么好看?
        Docker数据管理与镜像创建
        带研发团队后的日常思考1 初级管理者的困惑
        BIO,NIO和AIO是Java网络编程的三种模型学习教程
        数据结构-优先级队列
      16. 原文地址:https://blog.csdn.net/u013315062/article/details/127989254