SpringBoot原始碼學習(二) 釋出啟動事件
阿新 • • 發佈:2021-01-21
執行Spring應用程式
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 配置無頭屬性, 設定該應用程式即使沒有檢測到顯示器也允許啟動 configureHeadlessProperty(); // 從`META-INF/spring.factories`檔案集中獲取SpringApplicationRunListener的子類listener SpringApplicationRunListeners listeners = getRunListeners(args); // 開啟事件監聽,通知監聽者們(listener)執行相應操作 listeners.starting(); try { // 封裝命令列引數 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 準備環境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 配置忽略資訊 configureIgnoreBeanInfo(environment); // 列印banner Banner printedBanner = printBanner(environment); // 建立應用上下文 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 準備上下文 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 重新整理上下 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; }
獲取監聽器
呼叫getRunListeners(args)
方法,例項化一個SpringApplicationRunListeners
物件。 通過getSpringFactoriesInstances
方法讀取META-INF/spring.factories
進而例項化EventPublishingRunListener
。
/** * 從`META-INF/spring.factories`檔案集中獲取SpringApplicationRunListener的子類listener * @param args 命令列引數 * @return */ private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 例項化觀察模式的目標類, 在例項化時繫結監聽器(SpringApplicationRunListener子類) return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
注意: getSpringFactoriesInstances引數中的this,此方法將SpringApplication本身也傳遞過去了。
EventPublishingRunListener初始化
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); // 此時`names`只有`org.springframework.boot.context.event.EventPublishingRunListener`一個元素 for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); // 行參parameterTypes此時為`new Class<?>[] { SpringApplication.class, String[].class }` Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); // 實參此時為 `this, args`,this為SpringApplication例項, args為命令列引數 T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }
呼叫getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
通過反射例項化EventPublishingRunListener
。
EventPublishingRunListener例項化
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
// 命令列引數
this.args = args;
// 事件多播器
this.initialMulticaster = new SimpleApplicationEventMulticaster();
/**
* org.springframework.boot.devtools.restart.RestartApplicationListener,
* org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,
* org.springframework.boot.context.config.ConfigFileApplicationListener,
* org.springframework.boot.context.config.AnsiOutputApplicationListener,
* org.springframework.boot.context.logging.LoggingApplicationListener,
* org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,
* org.springframework.boot.autoconfigure.BackgroundPreinitializer,
* org.springframework.boot.context.config.DelegatingApplicationListener,
* org.springframework.boot.builder.ParentContextCloserApplicationListener,
* org.springframework.boot.devtools.logger.DevToolsLogFactory$Listener,
* org.springframework.boot.ClearCachesApplicationListener,
* org.springframework.boot.context.FileEncodingApplicationListener,
* org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
*/
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
依賴關係圖譜
SimpleApplicationEventMulticaster例項化
此原始碼為AbstractApplicationEventMulticaster中方法。
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
// 刪除代理的目標(如果已註冊),以避免重複呼叫同一偵聽器,暫時沒有發現有哪個監聽器符合條件
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
// 新增目標
this.defaultRetriever.applicationListeners.add(listener);
// 清理檢索快取
this.retrieverCache.clear();
}
}
啟動監聽器
listeners.starting();
void starting() {
// org.springframework.boot.context.event.EventPublishingRunListener
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
呼叫EventPublishingRunListener
中的starting()
方法。
@Override
public void starting() {
// 構造EventObject事件, source為application並廣播事件,通知各個監聽器
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
廣播Event
@Override
public void multicastEvent(ApplicationEvent event) {
// 過濾監聽器,為其廣播事件。resolveDefaultEventType(event)除了`org.springframework.http.client.PublisherEntity`和`org.springframework.context.PayloadApplicationEvent`其餘返回new ResolvableType(clazz)
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
/**
* 返回與給定事件型別匹配的ApplicationListeners的集合。不匹配的監聽器會被排除在外。
* org.springframework.boot.devtools.restart.RestartApplicationListener,
* org.springframework.boot.context.logging.LoggingApplicationListener,
* org.springframework.boot.autoconfigure.BackgroundPreinitializer,
* org.springframework.boot.context.config.DelegatingApplicationListener,
* org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
*/
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
// 用給定的事件呼叫給定的監聽器。
invokeListener(listener, event);
}
}
}
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);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
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;
}
}
}