Spring Boot启动过程

Spring Boot启动过程

1. SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

  • SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    	// 判断web类型,此处是通过ClassUtils.isPresent()来读取类是否存在,决定环境类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
    	// 给定类型,然后从spring.factories文件加载初始化器
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
    	// 给定类型,然后从spring.factories文件加载初始化器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    	// 使用StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(),
    	// 获取堆栈信息,获取名称为main方法的全类名,赋值
		this.mainApplicationClass = deduceMainApplicationClass();
	}

2.run(new Class<?>[] , args);

public ConfigurableApplicationContext run(String... args) {
    // 1、创建并启动计时监控类
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // 2、初始化应用上下文和异常报告集合
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 3、设置系统属性 `java.awt.headless` 的值,默认值为:true
    configureHeadlessProperty();
    // 4、创建所有 Spring 运行监听器并发布应用启动事件
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        // 5、初始化默认应用参数类
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);    
        // 6、根据运行监听器和应用参数来准备 Spring 环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 7、创建 Banner 打印类
        Banner printedBanner = printBanner(environment);
        // 8、创建应用上下文
        context = createApplicationContext();
        // 9、准备异常报告器
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);     
        // 10、准备应用上下文
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);     
        // 11、刷新应用上下文
        refreshContext(context);
        // 12、应用上下文刷新后置处理
        afterRefresh(context, applicationArguments);
        // 13、停止计时监控类
        stopWatch.stop();
        // 14、输出日志记录执行主类名、时间信息
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        // 15、发布应用上下文启动完成事件
        listeners.started(context);
        // 16、执行所有 Runner 运行器
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 17、发布应用上下文就绪事件
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    // 18、返回应用上下文
    return context;
}

根据序号详细说明 : **

2、初始化应用上下文和异常报告集合

ConfigurableApplicationContext context = null;
//新建异常报告集合 ,在 `9、准备异常报告器` 中准备完成
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

3、设置系统属性 java.awt.headless 的值,默认值为:true

对于一个 Java 服务器来说经常要处理一些图形元素,例如地图的创建或者图形和图表等。这些API基本上总是需要运行一个X-server以便能使用AWT(Abstract Window Toolkit,抽象窗口工具集)。然而运行一个不必要的 X-server 并不是一种好的管理方式。有时你甚至不能运行 X-server,因此最好的方案是运行 headless 服务器,来进行简单的图像处理。

4、创建所有 Spring 运行监听器并发布应用启动事件

	void starting();
	void environmentPrepared(ConfigurableEnvironment environment);
	void contextPrepared(ConfigurableApplicationContext context);
	void contextLoaded(ConfigurableApplicationContext context);
	void started(ConfigurableApplicationContext context);
	void running(ConfigurableApplicationContext context);
	void failed(ConfigurableApplicationContext context, Throwable exception);

4.1 listeners.starting()

public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        //EventPublishingRunListener#starting()
        listener.starting();
    }
}
4.1.1 EventPublishingRunListener#starting()
// SimpleApplicationEventMulticaster initialMulticaster
this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));

多路广播事件处理 :

multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType)
-| invokeListener(listener, event)
-| doInvokeListener(listener, event)
-| listener.onApplicationEvent(event)

注 : onApplicationEvent(event),其实看到此方法就可以见到真正处理的代码了!好开心!

6、根据运行监听器和应用参数来准备 Spring 环境

private ConfigurableEnvironment prepareEnvironment(
      SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   // listeners.`environmentPrepared(environment)`  与`4.1`节处理逻辑相似
   listeners.environmentPrepared(environment);
  
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader())
            .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);
   return environment;
}

10、准备应用上下文

private void prepareContext(ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   // 设置环境
   context.setEnvironment(environment);
   // 回调方法,Spring容器创建之后做一些额外的事
   postProcessApplicationContext(context);
   // SpringApplication的的初始化器开始工作
   applyInitializers(context);
   // 遍历调用SpringApplicationRunListener的contextPrepared方法。
   // 目前只是将这个事件广播器注册到Spring容器中
   listeners.contextPrepared(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 DefaultListableBeanFactory) {
      ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   // Load the sources
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   // 读取主类数据loader.load();
   load(context, sources.toArray(new Object[0]));
   // 遍历调用SpringApplicationRunListener的contextLoaded方法。
   listeners.contextLoaded(context);
}

11、*刷新应用上下文

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

11.1 prepareRefresh();

  • 设置Spring容器的启动时间,撤销关闭状态,开启活跃状态。

  • 初始化属性源信息(Property)

  • 验证环境信息里一些必须存在的属性

11.3 prepareBeanFactory(beanFactory);

  1. 设置classloader(用于加载bean),设置表达式解析器(解析bean定义中的一些表达式),添加属性编辑注册器(注册属性编辑器)
  2. 添加ApplicationContextAwareProcessor这个BeanPostProcessor。取消ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware这5个接口的自动注入。因为ApplicationContextAwareProcessor把这5个接口的实现工作做了
  3. 设置特殊的类型对应的bean。BeanFactory对应刚刚获取的BeanFactory;ResourceLoader、ApplicationEventPublisher、ApplicationContext这3个接口对应的bean都设置为当前的Spring容器
  4. 注入一些其它信息的bean,比如environment、systemProperties等

11.5 invokeBeanFactoryPostProcessors(beanFactory);

**调用链路 : **

invokeBeanFactoryPostProcessors(beanFactory)--->

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,getBeanFactoryPostProcessors())--->

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry)

for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
    postProcessor.postProcessBeanDefinitionRegistry(registry);
}

postProcessor.postProcessBeanDefinitionRegistry(registry)--->

int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException(
        "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
    throw new IllegalStateException(
        "postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);

processConfigBeanDefinitions(registry);

processConfigBeanDefinitions(registry)[创建config bean]--->

**读取主类包中的@Component注解 : **

ComponentScanAnnotationParser读取@ComponentScan注解,通过parse()加载packages属性.

Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass)

declaringClass是传入的主类,默认会读取该类的包位置


Spring Boot启动过程
https://www.blaaair.com/archives/springboot-jia-zai-guo-cheng
作者
Glo6f
发布于
2023年04月26日
许可协议