Spring Boot 2.x(十一)SpringBoot啓動配置原理

幾個重要的事件回調機制:

1、配置在META-INF/spring.factories

  1. ApplicationContextInitializer

  2. SpringApplicationRunlistener

2、需要放在ioc容器中

     3、ApplicationRunner

     4、CommandLineRunner

一、創建SpringApplication對象

快速創建一個工程,在SpringBootApplication類中,main方法作爲一個入口類,在在run()方法處打上斷點,debug運行;

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應用
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //從類路徑系找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然後保存起來
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //從類路徑系找到META-INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //從多個配置類中找到有main方法的主配置類
    this.mainApplicationClass = deduceMainApplicationClass();
}

  

二、運行run方法

接着上一步的繼續進行:

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    //獲取SpringApplicationRunListeners ,從類路徑下METTA-INF/spring.factories
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //回調所有的SpringApplicationRunListeners.starting方法
    listeners.starting();
    try {
        //封裝命令行參數
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //準備環境
	ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //創建環境完成後回調SpringApplicationRunListeners.environmentPrepared();表示環境準備完成
	configureIgnoreBeanInfo(environment);
	Banner printedBanner = printBanner(environment);
        //創建applicationContext,決定創建web的ioc還是普通的ioc
	context = createApplicationContext();
	exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
        //準備上下文環境;將environment保存到ioc中;而且applyInitializers()
        //applyInitializers():回調之前保存的所有的ApplicationContextInitializer的Initialize方法
        //回調所有的SpringApplicationRunListeners.contextPrepared()
	prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //prepareContext運行完成以後回調所有的SpringApplicationRunListeners的contextLoaded()
        //刷新容器;ioc容器初始化(如果是web應用還會創建嵌入式的tomcat);spring註解
        //掃描,創建,加載所有組件的地方;(配置類,組件,自動配置)
	refreshContext(context);
        //從ioc容器中獲取所有的ApplicationRunner和CommandLineRunner進行回調
        //ApplicationRunner先回調,CommandLineRunner再回調

	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);
    }
    //整個SpringBoot應用啓動完成以後返回啓動的ioc容器
    return context;
}

三、事件監聽機制

依次將上面的幾個監聽機制進行創建,

HelloApplicationContextInitializer:

public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer...initialize..." + applicationContext);
    }
}

HelloSpringApplicationRunListener:

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
    
    public HelloSpringApplicationRunListener(SpringApplication application, String[] args){

    }

    @Override
    public void starting() {
        System.out.println("SpringApplicationRunListener...starting...");
    }

    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        Object o = environment.getSystemProperties().get("os.name");
        System.out.println("SpringApplicationRunListener...environment" +o);
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...contextPrepared");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...contextLoaded");
    }

    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...started");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("SpringApplicationRunListener...running");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("SpringApplicationRunListener...failed");
    }
    

}

HelloApplicationRunner:

@Component
public class HelloAppicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner...run..");
    }
}

HelloCommandLineRuinner:

@Component
public class HelloCommandLineRunner implements CommandLineRunner{

    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner...run..." + Arrays.asList());
    }
}

前面提到的ApplicationContextInitializer和SpringApplicationRunlistener是需要進行配置的,配置的位置是在META-INF/spring.factories中,因此創建一個META-INF的文件夾,並創建spring.factories文件,

然後在spring.factories文件中進行配置:

org.springframework.context.ApplicationContextInitializer=\
com.itlaoqi.springbootspringbootapplication.listener.HelloApplicationContextInitializer

org.springframework.context.SpringApplicationRunListener=\
com.itlaoqi.springbootspringbootapplication.listener.HelloSpringApplicationRunListener

配置完成後啓動項目即可進行測試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章