概要

  • spring-boot-2.6.4.jar
  • org.springframework.boot.SpringApplication

入口 SpringApplication - 图1
image.png

run

  1. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  2. return new SpringApplication(primarySources).run(args);
  3. }
//*******

public ConfigurableApplicationContext run(String... args) {
        long startTime = System.nanoTime();

        //context 初始化
        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        ConfigurableApplicationContext context = null;

        //设置系统参数java.awt.headless为true,允许无其他硬件(键盘、鼠标、显示器)的情况下运行。
        configureHeadlessProperty();

        //listener 初始化
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //listener启动运行
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            //context初始化
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
            prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);

            // 
            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
            }
            listeners.started(context, timeTakenToStartup);

            //运行
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            //处理异常
            handleRunFailure(context, ex, listeners);
            throw new IllegalStateException(ex);
        }
        try {
            //listener 初始化完成
            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
            listeners.ready(context, timeTakenToReady);
        }
        catch (Throwable ex) {
            //处理异常
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

DefaultBootstrapContext 初始化

  • 会调用 bootstrapRegistryInitializers的 initialize 来初始化DefaultBootstrapContext
  • bootstrapRegistryInitializers最终是通过 SpringFactoriesLoader 从FACTORIES_RESOURCE_LOCATION = “META-INF/spring.factories” 这加载的
  • 所以 他把这个初始化DefaultBootstrapContext任务交给了在spring.factories指定的BootstrapRegistryInitializer类处理的
  • 初始化 DefaultBootstrapContext能干什么?//TODO

    • 实例管理 存map key是Class, value 是实例引用或 能实例化的工具类
    • listener管理 ```java

      private Collection getSpringFactoriesInstances(Class type) { return getSpringFactoriesInstances(type, new Class<?>[] {}); }

      private Collection getSpringFactoriesInstances(Class type, Class<?>[] parameterTypes, Object… args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }

public SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources) { //… this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); //… }

private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext)); return bootstrapContext; }

<a name="j7mTo"></a>
### SpringApplicationRunListeners初始化和运行

- 也是通过 SpringFactoriesLoader 从_FACTORIES_RESOURCE_LOCATION _= "META-INF/spring.factories" 这加载的
- spring-boot-xxx.jar里 有一个默认

org.springframework.boot.SpringApplicationRunListener=\<br />org.springframework.boot.context.event.EventPublishingRunListener   //TODO <br />�
```java
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = getClassLoader();
        // Use names and ensure unique to protect against duplicates
        Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }    


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);
    }
  • 执行 SpringApplicationRunListeners 中 applicationStartup 的start,这个applicationStartup是SpringApplication中初始化的用了ApplicationStartup._DEFAULT 即 _DefaultApplicationStartup
  • 执行每个 listener的starting方法
  • 执行step.tag, 这里的step是 DefaultApplicationStartup start函数返回的 DefaultStartupStep里的实现,你没什么实现的东西
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
        doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
                (step) -> {
                    if (mainApplicationClass != null) {
                        step.tag("mainApplicationClass", mainApplicationClass.getName());
                    }
                });
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
            Consumer<StartupStep> stepAction) {
        StartupStep step = this.applicationStartup.start(stepName);
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }
        step.end();
    }

ConfigurableEnvironment 初始化

  • ConfigurableEnvironments是管理配置文件的,
  • 参考 https://www.cnblogs.com/youzhibing/p/9622441.html
  • prepareEnvironment方法到底做了什么
    • 加载外部化配置资源到environment,包括命令行参数、servletConfigInitParams、servletContextInitParams、systemProperties、sytemEnvironment、random、application.yml(.yaml/.xml/.properties)等;

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach(environment);
        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 = convertEnvironment(environment);
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }


protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            environment.setConversionService(new ApplicationConversionService());
        }
        configurePropertySources(environment, args); //把命令行的把环境变量定义加进来
        configureProfiles(environment, args); // 从配置文件把环境变量定义参数加进来,这个SpringApplication没找到源码实现,应该不同子类里覆盖了
    }

ConfigurableApplicationContext 初始化更新

createApplicationContext

  • 下面这个applicationContextFactory会根据不同类型取初始化 ```java //….. ApplicationContextFactory DEFAULT = (webApplicationType) -> {
      try {
          switch (webApplicationType) {
          case SERVLET:
              return new 
                  ();
          case REACTIVE:
              return new AnnotationConfigReactiveWebServerApplicationContext();
          default:
              return new AnnotationConfigApplicationContext();
          }
      }    
    
    //………. /// protected ConfigurableApplicationContext createApplicationContext() {
      return this.applicationContextFactory.create(this.webApplicationType);
    
    }

- ApplicationContextFactory 的实现类 AnnotationConfigServletWebServerApplicationContext
   - //TODO

�
<a name="ZCKC6"></a>
### prepareContext

- 参考 [https://www.jianshu.com/p/bcdeb14ef710](https://www.jianshu.com/p/bcdeb14ef710)
```java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {

        context.setEnvironment(environment);
        //ApplicationContext的后置处理
        postProcessApplicationContext(context);
        //依次 ApplicationContextInitializer 列表的内对象的 initialize方法
        applyInitializers(context);

        listeners.contextPrepared(context);
        bootstrapContext.close(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
            ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
            if (beanFactory instanceof DefaultListableBeanFactory) {
                ((DefaultListableBeanFactory) beanFactory)
                        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
            }
        }
        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]));
        listeners.contextLoaded(context);
    }

postProcessApplicationContext

  • 主要是注册设置下面几个东西,从SpringApplication Environment设置到 context 和context的BeanFactory

    • beanNameGenerator
    • resourceLoader
    • addConversionService
      protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
         if (this.beanNameGenerator != null) {
             context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                     this.beanNameGenerator);
         }
         if (this.resourceLoader != null) {
             if (context instanceof GenericApplicationContext) {
                 ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
             }
             if (context instanceof DefaultResourceLoader) {
                 ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
             }
         }
         if (this.addConversionService) {
             context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
         }
      }
      

      applyInitializers

  • ApplicationContextInitializer 是个接口 //TODO 找些扩展例子

  • SpringApplication 的成员initializers 可以通过 setInitializers addInitializers 添加

protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }

listeners.contextPrepared(context);

  • SpringApplicationRunListener的contextPrepared没有实现 ,
    • 具体的 listenter 从 context获取信息 作一些操作 ```java void contextPrepared(ConfigurableApplicationContext context) { doWithListeners(“spring.boot.application.context-prepared”, (listener) -> listener.contextPrepared(context)); }
<a name="Uqk94"></a>
#### bootstrapContext.close(context);  启动上下文关闭

```java
public void close(ConfigurableApplicationContext applicationContext) {
        this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
    }

Add boot specific singleton beans

  • beanFactory.registerSingleton(“springApplicationArguments”, applicationArguments);
  • beanFactory.registerSingleton(“springBootBanner”, printedBanner);
  • setAllowCircularReferences //TODO 好像和循环依赖有关
  • setAllowBeanDefinitionOverriding

addBeanFactoryPostProcessor

  • ConfigurableApplicationContext没实现这个,要看context里设置的是
  • beanFactoryPostProcessors添加了这个 Processor后内,context的refresh时会按照一定顺序执行这个processer ```java if (this.lazyInitialization) {
          context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
      }
    

///。。。。。。。 @Override public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) { Assert.notNull(postProcessor, “BeanFactoryPostProcessor must not be null”); this.beanFactoryPostProcessors.add(postProcessor); }

<a name="FQMXv"></a>
#### Load the sources

- 注册bean
- 不同源码类型不同load
   - 其中一个分支是到 AnnotatedBeanDefinitionReader的 registerBean
```java
protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }

listeners.contextLoaded(context);

  • 具体看各自实例的实现
  • 下面是 EventPublishingRunListener里的实现

      public void contextLoaded(ConfigurableApplicationContext context) {
          for (ApplicationListener<?> listener : this.application.getListeners()) {
              if (listener instanceof ApplicationContextAware) {
                  ((ApplicationContextAware) listener).setApplicationContext(context);
              }
              context.addApplicationListener(listener);
          }
          this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
      }
    
  • 获取对应事件的listener去执行event

      @Override
      public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
          ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
          Executor executor = getTaskExecutor();
          for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
              if (executor != null) {
                  executor.execute(() -> invokeListener(listener, event));
              }
              else {
                  invokeListener(listener, event);
              }
          }
      }
    
  • 怎么获取listener ```java protected Collection> getApplicationListeners(

          ApplicationEvent event, ResolvableType eventType) {
    
      Object source = event.getSource();
      Class<?> sourceType = (source != null ? source.getClass() : null);
      ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    
      // Potential new retriever to populate
      CachedListenerRetriever newRetriever = null;
    
      // Quick check for existing entry on ConcurrentHashMap
      CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
      if (existingRetriever == null) {
          // Caching a new ListenerRetriever if possible
          if (this.beanClassLoader == null ||
                  (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                          (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
              newRetriever = new CachedListenerRetriever();
              existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
              if (existingRetriever != null) {
                  newRetriever = null;  // no need to populate it in retrieveApplicationListeners
              }
          }
      }
    
      if (existingRetriever != null) {
          Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
          if (result != null) {
              return result;
          }
          // If result is null, the existing retriever is not fully populated yet by another thread.
          // Proceed like caching wasn't possible for this current local attempt.
      }
    
      return retrieveApplicationListeners(eventType, sourceType, newRetriever);
    

    }

private Collection> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {

    List<ApplicationListener<?>> allListeners = new ArrayList<>();
    Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
    Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);

    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;
    synchronized (this.defaultRetriever) {
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }

    // Add programmatically registered listeners, including ones coming
    // from ApplicationListenerDetector (singleton beans and inner beans).
    for (ApplicationListener<?> listener : listeners) {
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                filteredListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }

    // Add listeners by bean name, potentially overlapping with programmatically
    // registered listeners above - but here potentially with additional metadata.
    if (!listenerBeans.isEmpty()) {
        ConfigurableBeanFactory beanFactory = getBeanFactory();
        for (String listenerBeanName : listenerBeans) {
            try {
                if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                    ApplicationListener<?> listener =
                            beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                    if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                        if (retriever != null) {
                            if (beanFactory.isSingleton(listenerBeanName)) {
                                filteredListeners.add(listener);
                            }
                            else {
                                filteredListenerBeans.add(listenerBeanName);
                            }
                        }
                        allListeners.add(listener);
                    }
                }
                else {
                    // Remove non-matching listeners that originally came from
                    // ApplicationListenerDetector, possibly ruled out by additional
                    // BeanDefinition metadata (e.g. factory method generics) above.
                    Object listener = beanFactory.getSingleton(listenerBeanName);
                    if (retriever != null) {
                        filteredListeners.remove(listener);
                    }
                    allListeners.remove(listener);
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Singleton listener instance (without backing bean definition) disappeared -
                // probably in the middle of the destruction phase
            }
        }
    }

    AnnotationAwareOrderComparator.sort(allListeners);
    if (retriever != null) {
        if (filteredListenerBeans.isEmpty()) {
            retriever.applicationListeners = new LinkedHashSet<>(allListeners);
            retriever.applicationListenerBeans = filteredListenerBeans;
        }
        else {
            retriever.applicationListeners = filteredListeners;
            retriever.applicationListenerBeans = filteredListenerBeans;
        }
    }
    return allListeners;
}
<a name="D3AVp"></a>
### refreshContext,
```java
private void refreshContext(ConfigurableApplicationContext context) {
        if (this.registerShutdownHook) {
            shutdownHook.registerApplicationContext(context);
        }
        refresh(context);
    }

shutdownHook

  • context 里塞了 ApplicationContextClosedListener的实例,
  • 把这个context 也赛道了自己 的contexts 一个Set
void registerApplicationContext(ConfigurableApplicationContext context) {
        addRuntimeShutdownHookIfNecessary();
        synchronized (SpringApplicationShutdownHook.class) {
            assertNotInProgress();
            context.addApplicationListener(this.contextCloseListener);
            this.contexts.add(context);
        }
    }

refresh(context) //重点

  • 默认的 refresh 实现 在AbstractApplicationContext

    public void refresh() throws BeansException, IllegalStateException {
          synchronized (this.startupShutdownMonitor) {
              StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
    
              // Prepare this context for refreshing.
              prepareRefresh();
    
              // Tell the subclass to refresh the internal bean factory.
              ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
              // Prepare the bean factory for use in this context.
              prepareBeanFactory(beanFactory);
    
              try {
                  // Allows post-processing of the bean factory in context subclasses.
                  postProcessBeanFactory(beanFactory);
    
                  StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                  // Invoke factory processors registered as beans in the context.
                  invokeBeanFactoryPostProcessors(beanFactory);
    
                  // Register bean processors that intercept bean creation.
                  registerBeanPostProcessors(beanFactory);
                  beanPostProcess.end();
    
                  // Initialize message source for this context.
                  initMessageSource();
    
                  // Initialize event multicaster for this context.
                  initApplicationEventMulticaster();
    
                  // Initialize other special beans in specific context subclasses.
                  onRefresh();
    
                  // Check for listener beans and register them.
                  registerListeners();
    
                  // Instantiate all remaining (non-lazy-init) singletons.
                  finishBeanFactoryInitialization(beanFactory);
    
                  // Last step: publish corresponding event.
                  finishRefresh();
              }
    
              catch (BeansException ex) {
                  if (logger.isWarnEnabled()) {
                      logger.warn("Exception encountered during context initialization - " +
                              "cancelling refresh attempt: " + ex);
                  }
    
                  // Destroy already created singletons to avoid dangling resources.
                  destroyBeans();
    
                  // Reset 'active' flag.
                  cancelRefresh(ex);
    
                  // Propagate exception to caller.
                  throw ex;
              }
    
              finally {
                  // Reset common introspection caches in Spring's core, since we
                  // might not ever need metadata for singleton beans anymore...
                  resetCommonCaches();
                  contextRefresh.end();
              }
          }
      }
    

    afterRefresh

listeners.started

callRunners

  • ApplicationRunner
    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);
              }
          }
      }
    

handleRunFailure

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();
                    shutdownHook.deregisterFailedApplicationContext(context);
                }
            }
        }
        catch (Exception ex) {
            logger.warn("Unable to close ApplicationContext", ex);
        }
        ReflectionUtils.rethrowRuntimeException(exception);
    }