導讀
在之前的文章中給大家介紹了Spring Boot的基本運行原理(鏈接),收到了很多讀者朋友們關於目前比較流行的微服務框架Spring Cloud的問題反饋。因此,在這篇文章中小碼哥打算和大家一起通過梳理下Spring Cloud的運行原理來相對全面的了解下Spring Cloud。
隨着微服務架構在越來越多的公司得到實踐和應用,基於Spring Cloud的這一套微服務生態框架體系,也在這個過程中得到大量的實踐和運用。雖然目前Service Mesh的概念也越來越得到關注,但是目前微服務開源框架中運用的比較廣泛的還是基於Spring Cloud的一套體系。作者之前所在的某共享單車公司也是基於這一套體系,實現了公司整體系統架構微服務化的過程。
從技術本身來來說,Spring Cloud並不是一個具體技術的名稱,也並不是一個完全重新定義的技術體系,而是基於Spring Boot這一高度自動化的應用開發框架,將各類業界比較知名的、得到過實踐反饋的開源服務治理相關的技術框架進行優化整合的這么一個框架。所以Spring Cloud本身並沒有太多的技術創新,而更多的是一種開發方式的優化與組合。
另外,Spring Cloud也不是一兩個技術的代名詞,而是一組框架的統稱。通過Spring Cloud基於Spring Boot的starter定制,實現開箱即用的目標,從而極大的簡化了以往利用各類相對碎片的服務治理框架所帶來的繁瑣。在Spring Cloud中你能通過一個很簡單的注解配置,就快速實現服務的注冊與發現,通過簡單的聲明式注解,就能夠實現服務的調用、負載均衡、限流、熔斷等機制,而這一切對應用開發者而言也都是透明的。
然而,也正是因為如此,所以在使用Spring Cloud進行微服務開發的過程中,我們也很容易忽視一些注解背后的底層技術實現,從而無法窺得其中的技術真諦及全貌。這一點在面試中也尤為不利,因為如果你說使用了這個技術棧,那么面試官必然會問到你底層技術的實現情況,況且真正要使用好一門技術,對其有一個相對整體到細致的掌握,也是運用好一門技術很重要的要求。
Spring Cloud核心組件
在上面的內容中我們說到Spring Cloud是一組框架的組合,那么組成這一組合的核心技術框架到底有那些呢?首先我們需要明確Spring Cloud微服務框架開發體系是基於Spring Boot應用開發模式的,也就是說如果想讓Spring Boot應用順利的實現微服務的功能,那么必然首先需要通過定制一套基於Spring Boot 的Starter以便快速進行框架依賴的集成與配置。所以,我們在基於Spring Cloud進行微服務開發時,在項目中就會通過引入“spring-cloud-starter-parent”父依賴來實現其他框架及組件的快速引入。
<parent> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-parent</artifactId> <version>Edgware.SR5</version> <relativePath /> </parent>
下面我們來看一下這個包的依賴引用關系:
通過上述依賴引用關系的梳理,不難發現,雖然我們只是很簡單的繼承了"spring cloud parent"這樣一個父依賴pom,但實際上卻是引入了整個Spring Boot的框架體系以及Spring Cloud框架體系的整個依賴。因此,我們就可以很方便地在基於Spring Cloud的微服務開發過程中,使用到Spring Boot以及Spring Cloud提供的各類組件框架的功能了。
那么Spring Cloud到底集成了那些核心框架來實現微服務體系的整體功能呢?以下我們抽取了Spring Cloud中整合的一些核心組件,如下圖所示:
在整個體系中最核心的組件莫過於服務注冊中心了,因為所有的微服務需要通過它實現服務的注冊與發現功能。而對於注冊中心的選擇,在Spring Cloud中使用得比較普遍的有基於java語言編寫的Eureka,以及基於go語言編寫的Consul。考慮到語言的異構問題,如go語言編寫的服務也能方便與java編寫的服務進行通信,之前作者所在的公司是使用了Consul作為服務注冊中心。
而當服務通過注冊中心完成服務的注冊后,服務間還需要一種便捷的方式進行通訊調用,在Spring Cloud中比較通用的方式是通過Feign進行服務調用。而調用時由於所有的微服務都支持通過consul或eureka進行多節點集群部署,所以在客戶端調用時,還需要實現負載均衡等功能,而這種客戶端調用時負載均衡功能的實現,在Spring Cloud中是通過Feign框架組合Ribbon框架來實現的。
在微服務體系中,另外一個比較核心的問題是需要實現服務的限流和熔斷。作為面向外部的服務,如果服務間的調用出現阻塞,那么就需要進行及時的限流,並通過熔斷來保證服務的基本可用性,此時Zuul及Hystrix就會通過注解的方式來提供這樣的功能機制。
最后一個必要且核心的問題,是服務配置的管理。是通過Spring Cloud Config這樣獨立配置管理服務來實現的,通過該組件我們可以實現在Spring Cloud體系中所有微服務應用配置的集中化管理。
Spring Cloud核心注解
以上就是Spring Cloud中必須的核心組件介紹,Spring Cloud正是因為整合來這些核心組件,就總體上實現了微服務架構體系的基本功能。而這些功能要通過友好地方式提供給開發者,那么還需要進行注解的定義與封裝,這樣開發者就只需要在代碼中簡單的引入一個注解,就可以實現這些功能了,那么接下來要的內容,就和大家一起看看Spring Cloud提供的核心注解,以及這些注解是怎么來實現微服務的相關功能的呢?
@EnableDiscoveryClient
服務的注冊與發現有多種實現方式如eureka、consul而@EnableDiscoveryClient注解則是定義在spring-cloud-commons包中,便於開發者快速實現服務注冊與發現的一個功能注解定義。在項目開發中,我們往往簡單的通過引入注解,就能夠實現微服務與服務注冊中心的相連,如:
@EnableFeignClients @EnableDiscoveryClient @EnableCircuitBreaker @SpringBootApplication public class Wallet { public static void main(String[] args) { SpringApplication.run(Wallet.class, args); } }
那么這個注解怎么這么神奇呢?下面我們就通過源碼分析的方式來看看@EnableDiscoveryClient是如何將服務注冊到consul中的?
如上圖所示,@EnableDiscoveryClient注解的定義中通過“@Import({EnableDiscoveryClientImportSelector.class})"類,此類通過定義“isEnabled()”表示開始服務注冊與發現的功能,然后其父類型“SpringFactoryImportSelector”通過“selectImports()"方法開始掃描eureka或者consul的集成starter依賴包。
以我們使用Consul作為注冊中心為例,我們需要在項目中引入“spring-cloud-starter-consul-discovery”這個依賴,而這個依賴的“META-INF/spring.factories”文件指向具體依賴“spring-cloud-consul-discovery”,而該依賴中的“META-INF/spring.factories”文件則包含了一系列自動配置類,如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration,\ org.springframework.cloud.consul.discovery.configclient.ConsulConfigServerAutoConfiguration,\ org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration,\ org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration,\ org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.consul.discovery.configclient.ConsulDiscoveryClientConfigServiceBootstrapConfiguration
然后這些自動配置類就會在應用啟動的時候進行初始化和加載,完成微服務與Consul的連接。
@ConditionalOnClass(ConfigServicePropertySourceLocator.class) @ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", matchIfMissing = false) @Configuration @ImportAutoConfiguration({ ConsulAutoConfiguration.class, ConsulDiscoveryClientConfiguration.class }) public class ConsulDiscoveryClientConfigServiceBootstrapConfiguration { }
如上述這個自動配置類,就會在存在配置屬性“spring.cloud.config.discovery.enabled=ture"的時候進行初始化。而這些初始化會與項目中關於Consul的配置進行匹配,如:
spring: cloud: consul: host: consul.${ci.environment.slug}.mobike.io config: format: FILES watch: delay: 30000 discovery: tags: api instance-id: ${ci.environment.slug}-${spring.application.name}-${spring.application.instance}
以上就基本上說清楚Spring Cloud進行服務自動發現注冊配置的基本原理了,實際上還是基於Spring Boot的機制來實現的。關於具體如何是怎么進行交互連接的,大家可以看看“spring-cloud-consul-discovery”的源碼。地址如下:
https://github.com/spring-cloud/spring-cloud-consul/tree/master/spring-cloud-consul-discovery
@EnableFeignClients
注解@EnableFeignClients
用於告訴框架掃描所有通過注解@FeignClient
定義的feign
客戶端。我們在服務消費方通過@EnableFeignClients注解開啟配置后,可以通過@FeignClient("user")注解后就可以進行服務調用了,而且實現了客戶端負載均衡。這是為什么呢?
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { this.registerDefaultConfiguration(metadata, registry); this.registerFeignClients(metadata, registry);//掃描FeignClient配置 }
因為,這個注解默認是會默認開啟Robbin代理的,而Robbin是實現客戶端負載均衡的一個組件,通過從Consul拉取服務節點信息,從而以輪詢的方式轉發客戶端調用請求至不同的服務端節點來實現負載均衡。
@EnableCircuitBreaker
要在SpringCloud中使用斷路器,需要加上@EnableCircuitBreaker注解。而該注解會引入Hystrix的配置,其過程與前面我們講解@EnableDiscoveryClient注解的過程一致。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({EnableCircuitBreakerImportSelector.class}) public @interface EnableCircuitBreaker { }
通過導入
EnableCircuitBreakerImportSelector類,開啟斷路器設置:
protected boolean isEnabled() { return ((Boolean)(new RelaxedPropertyResolver(this.getEnvironment())).getProperty("spring.cloud.circuit.breaker.enabled", Boolean.class, Boolean.TRUE)).booleanValue(); }
如果項目中引入了“spring-cloud-starter-hystrix”依賴包,那么在應用加載時就會初始化Hystrix相關的自動配置類。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.hystrix.HystrixAutoConfiguration,\ org.springframework.cloud.netflix.hystrix.security.HystrixSecurityAutoConfiguration org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\ org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerConfiguration
源碼地址如下:
https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-hystrix
Spring Cloud解決方案生態圈
事實上,采用微服務架構實現的分布式系統會面臨不少復雜性,以上核心組件只是實現了如服務發現&注冊、限流、熔斷等核心功能。還有很多的輔助場景,如分布式鏈路追蹤、安全等功能,這些輔助功能是為了確保在微服務架構下,各類服務的管理、監控、維護等需求能夠在一個完整的生態體系下實施。
因此,Spring Cloud除了一些核心的項目外,還有很多實現特定功能的組件框架,如Sleuth、Turbine等,下圖抽取了Spring Cloud生態中關注度比較高的一些框架,如下:
由於篇幅有限加上這些框架本身的實現也都是比較復雜,因此就不在這篇文章中一一展開了,大家可以根據自身項目的實際情況進行選擇,也可以通過源碼閱讀,更為細致的了解這些組件的實現原理。作者在后續的文章中也會找時間來逐步介紹它們,敬請關注!