SpringCloud升級之路2020.0.x版-9.如何理解並定製一個Spring Cloud元件

乾貨滿滿張雜湊發表於2021-08-13

本系列為之前系列的整理重啟版,隨著專案的發展以及專案中的使用,之前系列裡面很多東西發生了變化,並且還有一些東西之前系列並沒有提到,所以重啟這個系列重新整理下,歡迎各位留言交流,謝謝!~

我們實現的 Spring Cloud 微服務框架,裡面運用了許多 Spring Cloud 元件,並且對於某些元件進行了個性化改造。那麼對於某個 Spring Cloud 元件,我們一般是如何入手理解其中的原理呢?以及如何知道其中的擴充套件點呢?一般從下面兩個方面入手:

  1. 通過 spring-boot SPI 機制檢視模組的擴充套件點
  2. 檢視該模組實現的 NamedContextFactory

spring-core 專案中提供了 Spring 框架多種 SPI 機制,其中一種非常常用並靈活運用在了 Spring-boot 的機制就是基於 spring.factories 的 SPI 機制。

那麼什麼是 SPI(Service Provider)呢? 在系統設計中,為了模組間的協作,往往會設計統一的介面供模組之間的呼叫。面向的物件的設計裡,我們一般推薦模組之間基於介面程式設計,模組之間不對實現類進行硬編碼,而是將指定哪個實現置於程式之外指定。Java 中預設的 SPI 機制就是通過 ServiceLoader 來實現,簡單來說就是通過在META-INF/services目錄下新建一個名稱為介面全限定名的檔案,內容為介面實現類的全限定名,之後程式通過程式碼:

//指定載入的介面類,以及用來載入類的類載入器,如果類載入器為 null 則用根類載入器載入
ServiceLoader<SpiService> serviceLoader = ServiceLoader.load(SpiService.class, someClassLoader);
Iterator<SpiService> iterator = serviceLoader.iterator();
while (iterator.hasNext()){
    SpiService spiService = iterator.next();
}

獲取指定的實現類。

在 Spring 框架中,這個類是SpringFactoriesLoader,需要在META-INF/spring.factories檔案中指定介面以及對應的實現類,例如 Spring Cloud Commons 中的:

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor

其中指定了EnvironmentPostProcessor的實現HostInfoEnvironmentPostProcessor

同時,Spring Boot 中會通過SpringFactoriesLoader.loadXXX類似的方法讀取所有的EnvironmentPostProcessor的實現類並生成 Bean 到 ApplicationContext 中:

EnvironmentPostProcessorApplicationListener

//這個類也是通過spring.factories中指定ApplicationListener的實現而實現載入的,這裡省略
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
    //建立這個Bean的時候,會呼叫
    public EnvironmentPostProcessorApplicationListener() {
		this(EnvironmentPostProcessorsFactory
				.fromSpringFactories(EnvironmentPostProcessorApplicationListener.class.getClassLoader()));
	}
}

EnvironmentPostProcessorsFactory

static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
	return new ReflectionEnvironmentPostProcessorsFactory(
	        //通過 SpringFactoriesLoader.loadFactoryNames 獲取檔案中指定的實現類並初始化
			SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
}

META-INF/spring.factories 檔案中不一定指定的是介面以及對應的實現類,例如:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\

其中EnableAutoConfiguration是一個註解,LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration都是配置類並不是EnableAutoConfiguration的實現。那麼這個是什麼意思呢?EnableAutoConfiguration是一個註解,LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration都是配置類。spring.factories這裡是另一種特殊使用,記錄要載入的 Bean 類。EnableAutoConfiguration在註解被使用的時候,這些 Bean 會被載入。這就是spring.factories的另外一種用法。

EnableAutoConfiguration是 Spring-boot 自動裝載的核心註解。有了這個註解,Spring-boot 就可以自動載入各種@Configuration註解的類。那麼這個機制是如何實現的呢?

來看下EnableAutoConfiguration的原始碼
EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
	//排除的類
	Class<?>[] exclude() default {};
	//排除的Bean名稱
	String[] excludeName() default {};
}

我們看到了有 @Import 這個註解。這個註解是 Spring 框架的一個很常用的註解,是 Spring 基於 Java 註解配置的主要組成部分。

  1. 檢視 jar 包的 META-INF/spring.factories
  2. 檢視裡面的內容,尤其關注 org.springframework.boot.autoconfigure.EnableAutoConfiguration= 自動載入的配置類
  3. 檢視自動載入的配置類,關注哪些 Bean 可以擴充套件(例如,包含@ConditionalOnMissingBean 註解的 Bean)

我們一般想個性化定製都是針對呼叫不同微服務不同的 Bean 配置,所以其實要重點關注的就是這個模組擴充套件的 NamedContextFactory:

  1. 尋找這個元件擴充套件 NamedContextFactory 的類
  2. 檢視類的原始碼,檢視預設配置是什麼類,以及 Specification 是什麼類,以及如何獲取當前微服務的名稱。
  3. 根據預設配置類,檢視裡面的 Bean 有哪些,並且哪些可以被替換(例如,包含@ConditionalOnMissingBean 註解的 Bean)
  4. 根據 Specification 檢視擴充套件配置的方式

我們這裡拿 spring-cloud-loadbalancer 舉一個簡單例子,即:

spring-cloud-loadbalancer 中擴充套件 NamedContextFactory 的類是 LoadBalancerClientFactory,檢視 LoadBalancerClientFactory 的程式碼可以知道:

  1. 可以通過 loadbalancer.client.name 這個屬性獲取當前要建立的 Bean 是哪個微服務的
  2. 可以知道預設配置是 LoadBalancerClientConfiguration,再檢視它裡面的原始碼我們可以知道主要初始化兩個 Bean:
    1. ReactorLoadBalancer,負載均衡器,因為有 @ConditionalOnMissingBean 所以可以被替換,這就是我們的擴充套件點
    2. ServiceInstanceSupplier,提供例項資訊的 Supplier,因為有 @ConditionalOnMissingBean 所以可以被替換,這就是我們的擴充套件點
  3. Specification 為 LoadBalancerSpecification,再分析其呼叫可以知道,可以通過 @LoadBalancerClient@LoadBalancerClientsLoadBalancerClientConfiguration 的基礎上額外指定配置。

我們這一節詳細分析瞭如何使用以及分析改造一個 Spring Cloud 元件。下一節我們將開始具體分析我們實現的微服務框架的每一塊功能。

微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer

相關文章