SpringApplication 运行及源码解读

SpringApplication.run

@SpringBootApplication
public class AdvancedApplication {

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

在使用SpringBoot时,上面的代码我们一定很熟悉,这样写我们的程序就会自动创建并允许,但是Spring具体为我们做了什么我们就不得而知, 接下来我们就来阅读一下源码来一探究竟

源码分析

对于这段代码官方的解释是: Run the Spring application, creating and refreshing a new 大意为:运行Spring应用程序,创建并刷新一个新的

public ConfigurableApplicationContext run(String... args) {
    //1.
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //2.
    configureHeadlessProperty();
    //3.
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
    	ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //4.
    	ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //5.
    	configureIgnoreBeanInfo(environment);
    	Banner printedBanner = printBanner(environment);
        //6.
    	context = createApplicationContext();
        //7.
    	exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    			new Class[] { ConfigurableApplicationContext.class }, context);
        //8.
    	prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //9.
    	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, exceptionReporters, listeners);
    	throw new IllegalStateException(ex);
    }

    try {
    	listeners.running(context);
    }
    catch (Throwable ex) {
    	handleRunFailure(context, ex, exceptionReporters, null);
    	throw new IllegalStateException(ex);
    }
	return context;
}
  • 1.stopWatch.start(); 这里只是为了记录创建完成启动Spring所需要的时间,如:Started XXXApplication in 3.82 seconds (JVM running for 6.336)

  • 2.通过configureHeadlessProperty()配置属性

  • 3.通过getRunListeners()实例化监听器

这里请注意看 SpringApplicationRunListenersSpringApplicationRunListener,这时连个类,前者是后者的一个集合, 这时我们需在看getSpringFactoriesInstances()方法

如果您看过 EnableAutoConfiguration 源码解析 ,您很快就会明白他做了什么,这里主要是SpringFactoriesLoader.loadFactoryNames 是将spring.factories文件中的key存放在List中,在通过createSpringFactoriesInstances实例化 通过spring.factories 我们可以看出最终实例化的是 EventPublishingRunListener, 然后在进行 listeners.starting();来发送事件, 这里的starting()是调用的EventPublishingRunListener,当我查看其内部方法是,在实例化时又会预加载了ApplicationListener spring.factories 文件

  • 4.prepareEnvironment 配置环境

首先会通过(1)getOrCreateEnvironment()等方法创建和配置环境,(2)发布一个ApplicationEnvironmentPreparedEvent监听,代码如下,具体发布的内容,大家可以追踪一下

bindToSpringApplication进行了对spring.main的绑定,完成配置环境

  • 5.通过configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment)配置忽略一些bean,以及启动时的Banner

  • 6.创建ConfigurableApplicationContext

  • 7.getSpringFactoriesInstances 我们发现最终又是通过loadSpringFactories()方法读取spring.factories文件

  • 8.接下来我们继续查看prepareContext()

首先配置一个环境信息,之后会通过isteners.contextPrepared(context);发送ApplicationContextInitializedEvent

接下获取启动类,并将其作为bean加载到Spring 容器中,再通过 listeners.contextLoaded(context); 发送 ApplicationPreparedEvent

  • 9.refresh()方法,我们追踪代码会发现,最终走的是AbstractApplicationContext下方的代码 这个方法做了很多,如: 完成beanFactory设置, invoke ProcessBeanFactory ,国际化信息等,关于refresh()更多信息,请点击这里refresh源码解析

到这SpringBoot项目就完车了启动,最后callRunners()方法,这是我们经常用到的,当项目启动后区做一些处理,获取实现ApplicationRunner CommandLineRunner这两个接口

Last updated

Was this helpful?