最近在看Eureka源碼,本想快速解決這場沒有硝煙的戰役,不曾想阻塞性問題一個接一個。為正確理解這個框架,我不得不耐著性子,慢慢梳理這些讓人困惑的點。譬如本章要梳理的Lifecycle和SmartLifecycle。它們均為接口,其中后者繼承于前者,他們的類圖如下所示:
關于Lifecycle,網絡平臺給出的解釋是這樣的:它是Spring框架中的一個基礎接口,用于簡化管理有狀態的組件(譬如連接池、定時任務等)的初始化、啟動、停止等生命周期過程。它定義了以下核心方法:
- start():啟動組件。這通常涉及初始化必要的資源,使組件處于可操作狀態。
- stop():停止組件。執行必要的清理工作,釋放資源,使組件處于不可操作狀態。
- isRunning():該方法用于檢查組件當前是否正在運行。返回true表示組件已啟動且正在運行,返回false則表示未啟動或已停止。
與SmartLifecycle相比,Lifecycle接口較為簡單,不涉及啟動順序控制、自動啟動配置或生命周期回調等功能。它是更基礎的生命周期管理接口,適用于那些不需要復雜生命周期管理邏輯的組件。
下面就一起看一下Spring的這個組件是如何使用的,其實非常簡單,就是實現這個接口且實現其中定義的接口方法,比如下面這個自定義實現類:
package org.com.chinasoft.lifecycle;import org.springframework.context.Lifecycle;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyLifecycle implements Lifecycle {/*** A 組件的運行狀態*/private volatile boolean running = false;/*** 容器啟動后調用*/@Overridepublic void start() {System.out.println("lifecycle 容器啟動完成,啟動A組件...");running = true;}/*** 容器停止時調用*/@Overridepublic void stop() {System.out.println("lifecycle 收到關閉容器的信號,關閉A組件...");running = false;}/*** 檢查此組件是否正在運行。* 1. 只有該方法返回false時,start方法才會被執行。* 2. 只有該方法返回true時,stop(Runnable callback)或stop()方法才會被執行。*/@Overridepublic boolean isRunning() {System.out.println("lifecycle 檢查A組件的運行狀態:" + running);return running;}
}
那這個類是如何使用的呢?通過顯式調用ConfigurableApplicationContext上的start()/stop()方法實現的。具體可以看一下下面這個類:
package org.com.chinasoft;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication(exclude = KafkaAutoConfiguration.class)
public class EurekaServiceApplication {public static void main(String[] args) {ConfigurableApplicationContext ctx = SpringApplication.run(EurekaServiceApplication.class, args);ctx.start();ctx.stop();}}
為什么可以這樣呢?這是由于ConfigurableApplicationContext接口繼承了Lifecycle接口,關于這個接口的繼承結構可以看一下下面這幅圖:
從圖中可以很清楚的看到ConfigurableApplicationContext接口繼承了Lifecycle接口,由此所有實現該接口的類都擁有了Lifecycle的功能。就像案例中寫的那樣,為了演示Lifecycle接口的用法,我們顯式的調用了ConfigurableApplicationContext對象上的start()和stop()方法。執行結果如下圖所示:
這里既然提到了顯式調用,那如果不顯式調用是不是會不一樣?(網絡資料是這樣講的:如果不顯式調用不會有圖片中的輸出)。注釋上述調用代碼后的執行結果如下圖所示:
個人覺得這里就有點意思了,實際應用過程中,我們會顯式調用這個嗎?如果不會,這個調用的邏輯又在哪里呢?為了了解這個過程,還是先來看一下顯式調用的執行流程(紅色加粗加下劃線的部分即為實際的執行流程):
- AbstractApplicationContext#start()【這個實現方法來自于其實現的Lifecycle接口】
- AbstractApplicationContext#getLifecycleProcessor()【調用這個方法的主要目的是獲取Lifecycleprocessor對象,這個對象的實際類型為DefaultLifecycleProcessor】
- DefaultLifecycleProcessor#start()【調用該類中的start()方法。這個start()方法接著會調用DefaultLifecycleProcessor類上的startBeans()方法。這個方法首先從容器中拿到所有實現Lifecycle的bean,然后遍歷這個集合,將拿到的bean對象包裝到Map<Integer, LifecycleGrop>集合中(這個集合的value是一個LifecycleGroup對象),接著會不斷調用LifecycleGroup對象的add()方法將Lifecycle對象的名字及對象添加到LifecycleGroup對象中實際類型為List的members集合中,注意這個集合中元素的實際類型為LifecycleGroupMember。最后遍歷Map<Integer, LifecycleGrop>集合,然后調用LifecycleGroup對象上名為start()的方法,這個方法首先判斷members元素是否為空,如果不為空則排序,然后遍歷集合對象中的元素(LifecycleGroupMember),這個遍歷會首先對要處理的元素進行檢查,看其是否在LifecycleGroup對象上的lifecycleBeans集合中,如果在,則調用DefaultLifecycleProcessor類上的doStart()方法,如果一切順利最后就調用Lifecycle實現類上的start()方法。這個處理方法的具體實現邏輯如下所示:
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {Lifecycle bean = lifecycleBeans.remove(beanName);if (bean != null && !this.equals(bean)) {String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);for (String dependency : dependenciesForBean) {doStart(lifecycleBeans, dependency, autoStartupOnly);}if (!bean.isRunning() &&(!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {if (logger.isDebugEnabled()) {logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]");}try {bean.start();}catch (Throwable ex) {throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);}if (logger.isDebugEnabled()) {logger.debug("Successfully started bean '" + beanName + "'");}}}
}
實際調用跟蹤過程中發現,這個方法中Lifecycle類型的對象bean是一個代理對象。難道說所有實現該Lifecycle接口的對象都是通過動態代理的方式注入到了Spring容器中?關于這個問題暫且不表,先來看一下這個處理過程中用到的幾個類:
- DefaultLifecycleProcessor,這是一個實現了LifecycleProcessor接口(這個接口繼承了Lifecycle接口)和BeanFactoryAware接口的類。就測試案例中的操作來說:容器中所有對Lifecycle對象的操作都是通過這個類實現的。個人理解這個類的主要作用是:處理Spring Bean的生命周期。(大模型給出的解釋:該類是一個實現LifecycleProcessor和BeanFactoryAware接口的Java類。LifecycleProcessor接口定義了在Spring應用程序上下文中處理生命周期方法的策略,BeanFactoryAware接口允許類在被Spring容器實例化時獲取對BeanFactory的引用。這個類的作用是處理Spring Bean的生命周期。)
- LifecycleGroup,它是DefaultLifecycleProcessor類中的一個私有內部類,其擁有的屬性非常清晰:int類型的phase、long類型的timeout、boolean類型的autoStartupOnly、int類型的smartMemberCount、Map<String, ? extneds Lifecycle>類型的lifecycleBeans以及List<LifecycleGroupMember>類型的members。其中members用于存放包裝了Lifecycle對象的LifecycleGroupMember對象。另外這個類上還有add(String name, Lifecycle bean)方法、start()方法和stop()方法。其中第一個方法用于將Lifecycle對象添加到members集合中,這個方法在添加前會判斷這個對象是否是SmartLifecycle類型,如果是則將smartMemberCount的值自增1。start()方法的作用是在真正調用Lifecycle對象的start()方法前,做一些特殊處理,比如校驗(this.members.isEmpty())、對集合進行排序(Collections.sort(this.members))、遍歷members集合(調用DefaultLifecycleProcessor類上的doStart()方法,觸發Lifecycle對象上start()方法的調用)。stop()方法的處理邏輯與start()方法基本類似,有興趣的可以看一下源碼。個人理解這個類的主要作用就是對Lifecycle類型的對象做個分組,以方便管理,實現一些特殊功能。
- LifecycleGroupMember,它與LifecycleGroup類似,都是DefaultLifecycleProcessor類中的一個私有內部類,這個類實現了Comparable接口,可以實現排序。這個類中有兩個屬性,一個為String類型的name,一個是Lifecycle類型的bean,其中只有一個compareTo()方法,這個方法是實現排序的關鍵。個人理解這個類的作用就是讓系統中的Lifecycle對象具有排序功能。
現在讓我們一起回過頭來看一下這個問題:實際應用過程中,我們會顯式調用這個嗎?如果不會,這個調用的邏輯又在哪里呢?注意這個問題中提到的顯式調用,說的是Lifecycle接口中的start()及stop(),為了尋找這兩個方法的調用起點,我們可以利用一下擁有強大查找功能的集成工具idea。通過idea的查找工具,我們可以發現調用Lifecycle接口中的start()及stop()方法的地方有以下幾個:
- AbstractDiscoveryLifecycle的第243行this.start():AbstractDiscoveryLifecycle類實現了DiscoveryLifecycle接口(這個接口繼承了SmartLifecycle接口,其中SmartLifecycle接口又繼承了Lifecycle接口)。因此這里調用的就是AbstractDiscoveryLifecycle類中的start()方法,而這個方法的源調用方即ApplicationListener接口實現類AbstractDiscoveryLifecycle中的onApplicationEvent()方法
- RestartEndpoint的第203行this.context.start():ConfigurableApplicationContext類對象是RestartEndpoint中的屬性,而這個類又實現了Lifecycle接口,所以這一行調用的其實就是ConfigurableApplicationContext類父類AbstractApplicationContext中的start()方法
- EurekaDiscoveryClientConfiguration的第76行this.autoRegistration.start():這個調用最終調用的是EurekaAutoServiceRegistration類中的start()方法(這個類實現了SmartLifecycle接口)
- EurekaAutoServiceRegistration的第126行start():EurekaAutoServiceRegistration類實現了SmartLifecycle接口,所以這個start()方法中做了一些自己的邏輯
- AbstractApplicationContext的第1303行getLifecycleProcessor().start():這個就是前面梳理的哪個處理邏輯
- DefaultLifecycleProcessor的第175行bean.start():這個前面也梳理過,調用的就是Lifecycle實現類上的start()方法