本系列為之前系列的整理重啟版,隨著專案的發展以及專案中的使用,之前系列裡面很多東西發生了變化,並且還有一些東西之前系列並沒有提到,所以重啟這個系列重新整理下,歡迎各位留言交流,謝謝!~
我們實現的 Spring Cloud 微服務框架,裡面運用了許多 Spring Cloud 元件,並且對於某些元件進行了個性化改造。那麼對於某個 Spring Cloud 元件,我們一般是如何入手理解其中的原理呢?以及如何知道其中的擴充套件點呢?一般從下面兩個方面入手:
- 通過 spring-boot SPI 機制檢視模組的擴充套件點
- 檢視該模組實現的 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
是一個註解,LoadBalancerAutoConfiguration
與BlockingLoadBalancerClientAutoConfiguration
都是配置類並不是EnableAutoConfiguration
的實現。那麼這個是什麼意思呢?EnableAutoConfiguration
是一個註解,LoadBalancerAutoConfiguration
與BlockingLoadBalancerClientAutoConfiguration
都是配置類。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 註解配置的主要組成部分。
- 檢視 jar 包的 META-INF/spring.factories
- 檢視裡面的內容,尤其關注 org.springframework.boot.autoconfigure.EnableAutoConfiguration= 自動載入的配置類
- 檢視自動載入的配置類,關注哪些 Bean 可以擴充套件(例如,包含@ConditionalOnMissingBean 註解的 Bean)
我們一般想個性化定製都是針對呼叫不同微服務不同的 Bean 配置,所以其實要重點關注的就是這個模組擴充套件的 NamedContextFactory:
- 尋找這個元件擴充套件 NamedContextFactory 的類
- 檢視類的原始碼,檢視預設配置是什麼類,以及 Specification 是什麼類,以及如何獲取當前微服務的名稱。
- 根據預設配置類,檢視裡面的 Bean 有哪些,並且哪些可以被替換(例如,包含@ConditionalOnMissingBean 註解的 Bean)
- 根據 Specification 檢視擴充套件配置的方式
我們這裡拿 spring-cloud-loadbalancer 舉一個簡單例子,即:
spring-cloud-loadbalancer 中擴充套件 NamedContextFactory 的類是 LoadBalancerClientFactory,檢視 LoadBalancerClientFactory 的程式碼可以知道:
- 可以通過
loadbalancer.client.name
這個屬性獲取當前要建立的 Bean 是哪個微服務的 - 可以知道預設配置是
LoadBalancerClientConfiguration
,再檢視它裡面的原始碼我們可以知道主要初始化兩個 Bean:- ReactorLoadBalancer,負載均衡器,因為有
@ConditionalOnMissingBean
所以可以被替換,這就是我們的擴充套件點 - ServiceInstanceSupplier,提供例項資訊的 Supplier,因為有
@ConditionalOnMissingBean
所以可以被替換,這就是我們的擴充套件點
- ReactorLoadBalancer,負載均衡器,因為有
- Specification 為 LoadBalancerSpecification,再分析其呼叫可以知道,可以通過
@LoadBalancerClient
和@LoadBalancerClients
在LoadBalancerClientConfiguration
的基礎上額外指定配置。
我們這一節詳細分析瞭如何使用以及分析改造一個 Spring Cloud 元件。下一節我們將開始具體分析我們實現的微服務框架的每一塊功能。
微信搜尋“我的程式設計喵”關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer: