springboot startup source code analysis

overview

springboot startup class

package com.ahs.ahsaccount;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AhsAccountApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(AhsAccountApplication.class, args);
    }

}

run method

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

instance method

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    
    
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		 将启动类放入primarySources
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//根据classpath 下的类,推算当前web应用类型(REACTIVE, servlet)
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//去spring.factories 中去获取所有key:org.springframework.context.ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//去spring.factories 中去获取所有key: org.springframework.context.ApplicationListener
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		//根据main方法推算出mainApplicationClass
		this.mainApplicationClass = deduceMainApplicationClass();
	}

Get the startup class
Get the web application type
Read the ApplicationContextInitializer, and the ApplicationListener
calculates the class based on the main

run method

// SpringApplication.java

public ConfigurableApplicationContext run(String... args) {
    
    
    // 创建 StopWatch 对象,并启动。StopWatch 主要用于简单统计 run 启动过程的时长。
    StopWatch stopWatch = new StopWatch();
    //是记录了启动开始时间
    stopWatch.start();
    
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 配置 headless 属性
    configureHeadlessProperty();
    // 去spring.factroies中读取了SpringApplicationRunListener 的组件, 就是用来发布事件或者运行监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //发布1.ApplicationStartingEvent事件,在运行开始时发送
    listeners.starting();
    try {
    
    
        // 创建  ApplicationArguments 对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //  加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置。预初始化环境: 读取环境变量,读取配置文件信息(基于监听器)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        // 忽略beaninfo的bean
        configureIgnoreBeanInfo(environment);
        //   打印Banner 横幅
        Banner printedBanner = printBanner(environment);
        //  创建 Spring 容器。 根据webApplicationType创建Spring上下文
        context = createApplicationContext();
        //  异常报告器
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] {
    
     ConfigurableApplicationContext.class }, context);
        //  主要是调用所有初始化类的 initialize 方法,/预初始化spring上下文
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        //  初始化 Spring 容器。ioc流程
        refreshContext(context);
        // 执行 Spring 容器的初始化的后置逻辑。默认实现为空。
        afterRefresh(context, applicationArguments);
        // 停止 StopWatch 统计时长
        stopWatch.stop();
        // 打印 Spring Boot 启动的时长日志。
        if (this.logStartupInfo) {
    
    
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }
        //  通知 SpringApplicationRunListener 的数组,Spring 容器启动完成。
        listeners.started(context);
        // 调用 ApplicationRunner 或者 CommandLineRunner 的运行方法。
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
    
    
        // 如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    //  通知 SpringApplicationRunListener 的数组,Spring 容器运行中。
    try {
    
    
        listeners.running(context);
    } catch (Throwable ex) {
    
    
        //  如果发生异常,则进行处理,并抛出 IllegalStateException 异常
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

prepareEnvironment

// SpringApplication.java

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    
    
	// Create and configure the environment
	//  创建 ConfigurableEnvironment 对象,并进行配置
	//根据webApplicationType 创建Environment 创建就会读取: java环境变量和系统环境变量
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	// 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成。
	//发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件
	listeners.environmentPrepared(environment);
	//  绑定 environment 到 SpringApplication 上
	bindToSpringApplication(environment);
	//  如果非自定义 environment ,则根据条件转换
	if (!this.isCustomEnvironment) {
    
    
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	// 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。
	ConfigurationPropertySources.attach(environment);
	return environment;
}

prepareContext

// SpringApplication.java

private void prepareContext(ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    
    
    // <1> 设置 context 的 environment 属性
    context.setEnvironment(environment);
    // <2> 设置 context 的一些属性
    postProcessApplicationContext(context);
    // <3> 初始化 ApplicationContextInitializer
    //拿到之前读取到所有ApplicationContextInitializer的组件, 循环调用initialize方法
    applyInitializers(context);
    // <4> 通知 SpringApplicationRunListener 的数组,Spring 容器准备完成。
    listeners.contextPrepared(context);
    // <5> 打印日志
    if (this.logStartupInfo) {
    
    
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    // <6> 设置 beanFactory 的属性
    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
    // <7> 加载 BeanDefinition 们
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    // <8> 通知 SpringApplicationRunListener 的数组,Spring 容器加载完成。
    listeners.contextLoaded(context);
}

refreshContext

// SpringApplication.java


private void refreshContext(ConfigurableApplicationContext context) {
    
    
	// <1> 开启(刷新)Spring 容器
	refresh(context);
	// <2> 注册 ShutdownHook 钩子
	if (this.registerShutdownHook) {
    
    
		try {
    
    
			context.registerShutdownHook();
		} catch (AccessControlException ex) {
    
    
			// Not allowed in some environments.
		}
	}
}

callRunners

extension point

// SpringApplication.java

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    
    
    // <1> 获得所有 Runner 们
    List<Object> runners = new ArrayList<>();
    // <1.1> 获得所有 ApplicationRunner Bean 们
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    // <1.2> 获得所有 CommandLineRunner Bean 们
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // <1.3> 排序 runners
    AnnotationAwareOrderComparator.sort(runners);
    // <2> 遍历 Runner 数组,执行逻辑
    for (Object runner : new LinkedHashSet<>(runners)) {
    
    
        if (runner instanceof ApplicationRunner) {
    
    
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
    
    
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

Summarize

1. Initialize SpringApplication Read listener ApplicationContextInitializer from spring.factories.
2. Run the run method
3. Read environment variable configuration information, etc.
4. Create a springApplication context: ServletWebServerApplicationContext
5. Pre-initialize the context
6. Call refresh to load the ioc container and load all automatic configuration classes
7. Create a servlet container
8. Throughout the process Many listeners will be called multiple times for external

Guess you like

Origin blog.csdn.net/qq_42600094/article/details/131076901