SpringBoot(四)SpringApplication啟動類運行階段 - SpringApplicationRunListener


前言

        最近在學習Spring Boot相關的課程,過程中以筆記的形式記錄下來,方便以后回憶,同時也在這里和大家探討探討,文章中有漏的或者有補充的、錯誤的都希望大家能夠及時提出來,本人在此先謝謝了!

開始之前呢,希望大家帶着幾個問題去學習:
1、Spring Boot SpringApplication 是什么?
2、整體流程或結構是怎樣的?
3、重點內容或者核心部分是什么?
4、怎么實現的?
5、是怎么和 Spring 關聯起來的?
這是對自我的提問,我認為帶着問題去學習,是一種更好的學習方式,有利於加深理解。好了,接下來進入主題。

1、起源

        上篇文章我們講了 SpringApplication 的准備階段,在這個階段,完成了運行時所需要准備的資源,如:initializerslisteners等。而這篇文章我們就來講講 SpringApplication 的運行階段,在這個階段,它是如何啟動 Spring 應用上下文的,且如何與 Spring 事件結合起來,形成完整的 SpringApplication 生命周期的。

注:本篇文章所用到的 Spring Boot版本是 2.1.6.BUILD-SNAPSHOT

2、SpringApplication 運行階段

        上篇文章我們講了 SpringApplication 的構造方法,這里我們就來講講 SpringApplication 的核心,也就是run方法,代碼如下:

public class SpringApplication {

    ...
        
    public ConfigurableApplicationContext run(String... args) {
    	// 這是 Spring 的一個計時器,計算代碼的執行時間(ms級別)
    	StopWatch stopWatch = new StopWatch();
    	stopWatch.start();
    	
    	// 這倆變量在后面賦值處進行說明
    	ConfigurableApplicationContext context = null;
    	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    	
    	// 用來設置java.awt.headless屬性值
    	configureHeadlessProperty();
    	
    	// 該對象屬於組合模式的實現,核心是內部關聯的 SpringApplicationRunListener 集合,SpringApplicationRunListener 是 Spring Boot 的運行時監聽器
    	SpringApplicationRunListeners listeners = getRunListeners(args);
    	// 會在不同的階段調用對應的方法,這里表示啟動run方法被調用
    	listeners.starting();
    	
    	try {
    	
    	    // 用來獲取 SpringApplication.run(args)傳入的參數
    		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    		
    		// 獲取 properties 配置文件
    		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
    		
    		// 設置 spring.beaninfo.ignore 的屬性值,判斷是否跳過搜索BeanInfo類
    		configureIgnoreBeanInfo(environment);
    		
    		// 這里是項目啟動時,控制台打印的 Banner
    		Banner printedBanner = printBanner(environment);
    		
    		// 這里就是創建 Spring 應用上下文
    		context = createApplicationContext();
    		
    		// 獲取 spring.factories 中key為 SpringBootExceptionReporter 的類名集合
    		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
    				new Class[] { ConfigurableApplicationContext.class }, context);
    				
    		// 這里是准備 Spring 應用上下文
    		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    		
    		// 這里是啟動 Spring 應用上下文,底層調用的是 ApplicationContext 的 refresh() 方法,到這里就正式進入了 Spring 的生命周期,同時,SpringBoot的自動裝配特性也隨之啟動
    		refreshContext(context);
    		
    		// 里面是空的,猜測應該是交由開發人員自行擴展
    		afterRefresh(context, applicationArguments);
    		stopWatch.stop();
    		
    		// 這里打印啟動信息
    		if (this.logStartupInfo) {
    			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    		}
    		
    		// ApplicationContext 啟動時,調用該方法
    		listeners.started(context);
    		
    		// 項目啟動后,做的一些操作,開發人員可自行擴展
    		callRunners(context, applicationArguments);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, listeners);
    		throw new IllegalStateException(ex);
    	}
    
    	try {
    	
    	    // ApplicationContext 啟動完成時,調用該方法
    		listeners.running(context);
    	}
    	catch (Throwable ex) {
    		handleRunFailure(context, ex, exceptionReporters, null);
    		throw new IllegalStateException(ex);
    	}
    	return context;
    }
    
    ...
}

上面就是整個過程的概覽,可以看到,在運行階段執行的操作比較多,雖然看起來雜亂無章,但其實還是有規律可循的。比如,執行的 SpringApplicationRunListeners 中的階段方法,剛啟動階段的 starting 、已啟動階段的 started 、啟動完成階段的 running 等。還有對應的 Spring 應用上下文的創建、准備、啟動操作等。接下來,就對里面的幾個核心對象進行討論。

2.1 SpringApplicationRunListeners 結構

我們先來看看 SpringApplicationRunListeners 對象,從代碼可以看出該對象是由 getRunListeners 方法創建的:

private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	return new SpringApplicationRunListeners(logger,
			getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

可以看到,通過傳入的 getSpringFactoriesInstances 方法的返回值,執行 SpringApplicationRunListeners 的構造方法,進行對象的創建。接着看 getSpringFactoriesInstances 方法:

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;
}

看到這大家應該比較熟悉了,通過前面幾篇文章的討論我們知道,該方法通過 SpringFactoriesLoader.loadFactoryNames 返回所有 classpass 下的 spring.factories 文件中 key 為 SpringApplicationRunListener 的實現類集合。如 Spring Boot 的內建實現:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

最后,就是將該集合傳入 SpringApplicationRunListeners 的構造方法:

class SpringApplicationRunListeners {

    ...

	private final List<SpringApplicationRunListener> listeners;

	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}

	...

}

里面是將集合賦值到 listeners 屬性,可以看到 SpringApplicationRunListeners 屬於組合模式的實現,核心其實是內部關聯的 SpringApplicationRunListener 對象集合,當外部調用該階段方法時,就會迭代執行集合中 SpringApplicationRunListener 對應的方法。所以接下來我們就來討論 SpringApplicationRunListener

2.1.1 SpringApplicationRunListener 事件和監聽機制

SpringApplicationRunListener 負責在 SpringBoot 的不同階段廣播相應的事件,然后調用實際的 ApplicationListener 類,在該類的 onApplicationEvent 方法中,根據不同的 Spring Boot 事件執行相應操作。整個過程大概如此,接下來進行詳細討論,先來看看 SpringApplicationRunListener 定義:

public interface SpringApplicationRunListener {

    // 在run()方法開始執行時被調用,表示應用剛剛啟動,對應的 Spring Boot 事件為 ApplicationStartingEvent
	void starting();

    // ConfigurableEnvironment 構建完成時調用,對應的 Spring Boot 事件為 ApplicationEnvironmentPreparedEvent
	void environmentPrepared(ConfigurableEnvironment environment);

    // ApplicationContext 構建完成時調用,對應的 Spring Boot 事件為 ApplicationContextInitializedEvent
	void contextPrepared(ConfigurableApplicationContext context);

    // ApplicationContext 完成加載但還未啟動時調用,對應的 Spring Boot 事件為 ApplicationPreparedEvent
	void contextLoaded(ConfigurableApplicationContext context);

    // ApplicationContext 已啟動,但 callRunners 還未執行時調用,對應的 Spring Boot 事件為 ApplicationStartedEvent
	void started(ConfigurableApplicationContext context);

    // ApplicationContext 啟動完畢被調用,對應的 Spring Boot 事件為 ApplicationReadyEvent
	void running(ConfigurableApplicationContext context);

    // 應用出錯時被調用,對應的 Spring Boot 事件為 ApplicationFailedEvent
	void failed(ConfigurableApplicationContext context, Throwable exception);

}

我們來看看它的實現類,也就是上面加載的 spring.factories 文件中的 EventPublishingRunListener 類,該類也是 Spring Boot 內建的唯一實現類,具體廣播事件的操作在該類中進行,代碼如下:

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

	...

}

可以看到,通過構造方法創建 EventPublishingRunListener 實例的過程中,調用了 getListeners 方法,將 SpringApplication 中所有 ApplicationListener 監聽器關聯到了 initialMulticaster 屬性中。沒錯,這里的 ApplicationListener 監聽器就是上篇文章中在 SpringApplication 准備階段從 spring.factories 文件加載的 key 為 ApplicationListener 的實現類集合,該實現類集合全部重寫了 onApplicationEvent 方法。

2.1.2 SimpleApplicationEventMulticaster 廣播器

這里又引出了另一個類, 也就是 SimpleApplicationEventMulticaster ,該類是 Spring 的事件廣播器,也就是通過它來廣播各種事件。接着,當外部迭代的執行到 EventPublishingRunListenerstarting 方法時,會通過 SimpleApplicationEventMulticastermulticastEvent 方法進行事件的廣播,這里廣播的是 ApplicationStartingEvent 事件,我們進入 multicastEvent 方法:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    ...
    
    @Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(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);
			}
		}
	}
}

通過 getApplicationListeners 方法,根據事件類型返回從上面關聯的 ApplicationListener 集合中篩選出匹配的 ApplicationListener 集合,根據 Spring Boot 版本的不同,在這個階段獲取到的監聽器也有可能不同,如 2.1.6.BUILD-SNAPSHOT 版本返回的是:
image

然后依次遍歷這些監聽器,同步或異步的調用 invokeListener 方法:

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
	if (errorHandler != null) {
		try {
			doInvokeListener(listener, event);
		}
		catch (Throwable err) {
			errorHandler.handleError(err);
		}
	}
	else {
		doInvokeListener(listener, event);
	}
}

...

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

可以看到,最終調用的是 doInvokeListener 方法,在該方法中執行了 ApplicationListeneronApplicationEvent 方法,入參為廣播的事件對象。我們就拿其中一個的監聽器來看看 onApplicationEvent 中的實現,如 BackgroundPreinitializer 類:

public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {

	...
	
	@Override
	public void onApplicationEvent(SpringApplicationEvent event) {
		if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
				&& event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
			performPreinitialization();
		}
		if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
				&& preinitializationStarted.get()) {
			try {
				preinitializationComplete.await();
			}
			catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			}
		}
	}
	
	...
}

在該方法中,通過 instanceof 判斷事件的類型,從而進行相應的操作。該監聽器主要的操作是新建一個后台線程去執行那些耗時的初始化工作,包括驗證器、消息轉換器等。LoggingApplicationListener 監聽器則是對 Spring Boot 的日志系統做一些初始化的前置操作。另外兩個監聽器在該階段無任何操作。

至此,SpringBoot 事件機制的整體流程大概如此,我們簡要回顧一下幾個核心組件:

  • SpringApplicationRunListeners:首先,在 run 方法的執行過程中,通過該類在 SpringBoot 不同的階段調用不同的階段方法,如在剛啟動階段調用的 starting 方法。

  • SpringApplicationRunListener:而 SpringApplicationRunListeners 屬於組合模式的實現,它里面關聯了 SpringApplicationRunListener 實現類集合,當外部調用階段方法時,會迭代執行該集合中的階段方法。實現類集合是 spring.factories 文件中定義好的類。這里是一個擴展點,詳細的后面述說。

  • EventPublishingRunListener:該類是 Spring Boot 內置的 SpringApplicationRunListener 唯一實現類,所以,當外部調用各階段的方法時,真正執行的是該類中的方法。

  • SimpleApplicationEventMulticaster:在階段方法中,會通過 SpringSimpleApplicationEventMulticaster 事件廣播器,廣播各個階段對應的事件,如這里的 starting 方法廣播的事件是 ApplicationStartingEvent

  • ApplicationListener:最后 ApplicationListener 的實現類也就是 Spring Boot 監聽器會監聽到廣播的事件,根據不同的事件,進行相應的操作。這里的 Spring Boot 監聽器是也是在 spring.factories 中定義好的,這里我們也可自行擴展。

到這里 Spring Boot 事件監聽機制差不多就結束了,值得注意的是 Spring Boot 監聽器實現的是 SpringApplicationListener 類,事件類最終繼承的也是 SpringApplicationEvent 類,所以,Spring Boot 的事件和監聽機制都基於 Spring 而實現的。

2.2 ApplicationArguments 加載啟動參數

        當執行完 listeners.starting 方法后,接着進入構造 ApplicationArguments 階段:

public class SpringApplication {

    ...
    
    public ConfigurableApplicationContext run(String... args) {
		
		...
		
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			
			...
		}
	}
	
	...
}

該類是用於簡化 Spring Boot 應用啟動參數的封裝接口,我們啟動項目時輸入的命令參數會封裝在該類中。一種是通過 IDEA 輸入的參數,如下:
image

另一種是 springboot jar包運行時傳遞的參數:cmd中運行java -jar xxx.jar name=張三 pwa=123

然后,可以通過 @Autowired 注入 ApplicationArguments 的方式進行使用:

public class Test {

    @Autowired
    private ApplicationArguments applicationArguments;

    public void getArgs() {
        // 獲取 args 中的所有 non option 參數
		applicationArguments.getNonOptionArgs();

		// 獲取 args 中所有的 option 參數的 name
		applicationArguments.getOptionNames();

		// 獲取傳遞給應用程序的原始未處理參數
		applicationArguments.getSourceArgs();

		// 獲取 args 中指定 name 的 option 參數的值
		applicationArguments.getOptionValues("nmae");

		// 判斷從參數中解析的 option 參數是否包含指定名稱的選項
		applicationArguments.containsOption("name");
    }
}

2.3 ConfigurableEnvironment 加載外部化配置

        接着進入構造 ConfigurableEnvironment 的階段,該類是用來處理我們外部化配置的,如 propertiesYAML 等,提供對配置文件的基礎操作。當然,它能處理的外部配置可不僅僅如此,詳細的在下篇文章討論,這里我們進行簡要了解即可,進入創建該類的 prepareEnvironment 方法:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

這里通過 getOrCreateEnvironment 方法返回具體的 Environment

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
			return new StandardServletEnvironment();
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}

可以看到,這里通過 webApplicationType 屬性來判斷當前應用的類型,有 ServletReactive 、 非Web 3種類型,該屬性也是在上篇文章中 SpringApplication 准備階段確定的,這里我們通常都是 Servlet 類型,返回的是 StandardServletEnvironment 實例。

之后,還調用了 SpringApplicationRunListenersenvironmentPrepared 階段方法,表示 ConfigurableEnvironment 構建完成,同時向 Spring Boot 監聽器發布 ApplicationEnvironmentPreparedEvent 事件。監聽該事件的監聽器有:
image

2.4 ConfigurableApplicationContext 創建 Spring 應用上下文

        這里通過 createApplicationContext 方法創建 Spring 應用上下文,實際上 Spring 的應用上下文才是驅動 Spring Boot 的核心引擎:

public class SpringApplication {

    ...

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

    public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

    public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

    ...

    protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
	
	...
}

這里也是通過 webApplicationType 屬性來確定應用類型從而創建 String 上下文,上篇文章說到該屬性值是在 Spring Boot 准備階段推導出來的。這里我們的應用類型是 Servlet ,所以創建的是 AnnotationConfigServletWebServerApplicationContext 對象。創建完 Spring 應用上下文之后,執行 prepareContext 方法進入准備上下文階段:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	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");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

我們來看看主要做了哪些操作:

  1. 設置了 Spring 應用上下文的 ApplicationArguments,上面說過是處理外部化配置的,具體類型為 StandardServletEnvironment

  2. Spring 應用上下文后置處理,主要是覆蓋當前 Spring 應用上下文默認所關聯的 ResourceLoaderClassLoader

  3. 執行 Spring 的初始化器,上篇文章說過在 Spring Boot 准備階段初始化了一批在 spring.factories 文件中定義好的 ApplicationContextInitializer ,這里就是執行它們的 initialize 方法,同時這里也是一個擴展點,后面詳細討論。

  4. 執行 SpringApplicationRunListenerscontextPrepared 階段方法,表示 ApplicationContext 准備完成,同時向 Spring Boot 監聽器發布 ApplicationContextInitializedEvent 事件 。

  5. springApplicationArgumentsspringBootBanner 注冊為 Bean

  6. 加載 Spring 應用上下文的配置源,也是在上篇文章 Spring Boot 准備階段獲取的 primarySourcessourcesprimarySources 來源於 SpringApplication 構造器參數,sources 則來源於自定義配置的 setSources 方法。

  7. 最后執行 SpringApplicationRunListenerscontextLoaded 階段方法,表示 ApplicationContext 完成加載但還未啟動,同時向 Spring Boot 監聽器發布 ApplicationPreparedEvent 事件 。

接下來就是真正啟動階段,執行的是 refreshContext 方法:

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}
protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
	((AbstractApplicationContext) applicationContext).refresh();
}

可以看到,底層調用的是 AbstractApplicationContextrefresh 方法,到這里 Spring 應用正式啟動,Spring Boot 核心特性也隨之啟動,如自動裝配。隨后執行 SpringApplicationRunListenersstarted 階段方法,表示 ApplicationContext 已啟動,同時向 Spring Boot 監聽器發布 ApplicationStartedEvent 事件 。但還未啟動完成,后面還有一個 callRunners 方法,一般來講,里面執行一些我們自定義的操作。之后 Spring 應用才算啟動完成,隨后調用 running 方法,發布 ApplicationReadyEvent 事件。至此,SpringApplication 運行階段結束。

3、總結

        最后來對 SpringApplication 運行階段做一個總結。這個階段核心還是以啟動 Spring 應用上下文為主,同時根據應用類型來初始化不同的上下文對象,但這些對象的基類都是 Spring ConfigurableApplicationContext 類。且在啟動的各個階段中,使用 SpringApplicationRunListeners 進行事件廣播,回調 Spring Boot 的監聽器。同時還初始化了 ApplicationArgumentsConfigurableEnvironment 等幾個組件。下篇文章我們就來討論 Spring Boot 的外部化配置部分,來看看為什么外部的各個組件,如 RedisDubbo 等在 properties 文件中進行相應配置后,就可以正常使用。

以上就是本章的內容,如過文章中有錯誤或者需要補充的請及時提出,本人感激不盡。



參考:

《Spring Boot 編程思想》
https://www.cnblogs.com/youzhibing/p/9603119.html
https://www.jianshu.com/p/b86a7c8b3442
https://www.cnblogs.com/duanxz/p/11243271.html
https://www.jianshu.com/p/7a674c59d76e


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM