官术网_书友最值得收藏!

2.2 Spring Cloud特性

云原生應用程序開發風格鼓勵在持續交付和價值驅動開發上采取最佳的實踐策略,Spring Cloud提供了多種方式來促進云原生開發風格。Spring Cloud提供了一系列組件,可以在分布式系統中直接使用,這些組件大大降低了分布式系統的搭建和開發難度。

這些組件大多數由Spring Boot提供,Spring Cloud在此基礎上添加了分布式系統的相關特性。Spring Cloud依賴于Spring Cloud Context和Spring Cloud Commons兩個公共庫,其中Spring Cloud Context為Spring Cloud應用程序上下文(ApplicationContext)提供了大量的實用工具和特性服務,而Spring Cloud Common是針對不同的Spring Cloud實現(如Spring Cloud Netflix Eureka和Spring Cloud Consul兩種不同的服務注冊與發現實現)提供上層抽象和公共類。

接下來將從這兩個庫著手,對Spring Cloud的相關特性進行簡要介紹。

2.2.1 Spring Cloud Context:應用上下文

使用過Spring Boot的讀者都或多或少地了解如何使用Spring構建應用,比如,配置一般都需要放置在統一的位置,暴露用于管理的網絡接口等。Spring Cloud在這些最佳實踐之上提供了新的特性,來適配微服務架構下的運維環境。

1. Bootstrap上下文

除了應用上下文配置(application.yml或者application.properties)之外,Spring Cloud應用程序還額外提供與Bootstrap上下文配置相關的應用屬性。Bootstrap上下文對于主程序來說是一個父級上下文,它支持從外部資源中加載配置文件,和解密本地外部配置文件中的屬性。Bootstrap上下文和應用上下文將共享一個環境(Environment),這是所有Spring應用程序的外部屬性來源。一般來講,Bootstrap上下文中的屬性優先級較高,所以它們不能被本地配置所覆蓋。

Bootstrap上下文使用與主程序不同的規則來加載外部配置。因此bootstrap.yml用于為Bootstrap上下文加載外部配置,區別于應用上下文的application.yml或者application. properties。一個簡單的bootstrap.yml的例子如下所示:

        spring:
            application:
                name: my-application
            cloud:
                config:
                    uri: ${CONFIG_SERVER:http://localhost:8080}

如果想要禁止Bootstrap引導過程,可以在bootstrap.yml中設置,如下所示:

        spring:
            cloud:
                  bootstrap:
                      enabled: false

2.應用上下文層級

Spring的上下文有一個特性:子級上下文將從父級中繼承屬性源和配置文件。如果通過SpringApplication或者SpringApplicationBuilder來構建應用程序上下文,那么Bootstrap上下文將會成為該應用程序上下文的父級上下文。

在Bootstrap上下文中掃描到的非空的PropertySourceLocators會以高優先級添加到CompositePropertySource中。如果通過bootstrap.yml來配置Bootstrap上下文,且在設定好父級上下文的情況下,bootstrap.yml中的屬性會添加到子級的上下文。它們的優先級低于application.yml和其他添加到子級中作為創建Spring Boot應用的屬性源。

基于屬性源的排序規則,Bootstrap上下文中的屬性優先,但是需要注意這些屬性并不包含任何來自bootstrap.yml的數據。bootstrap.yml中的屬性具備非常低的優先級,因此可以作為默認值。

可以簡單地將父級上下文設置為應用上下文來擴展上下文的層次結構。Bootstrap上下文將會是最高級別上下文的父級。每一個在層次結構中的上下文都有它自己的Bootstrap屬性源(可能為空),來避免無意中將父級上下文中的屬性傳遞到它的后代中。層次結構中的每一個上下文原則上應該擁有自己不同的spring.application.name,以便在有配置中心的時候也能有不同的遠程屬性源。來自子級上下文的屬性可以覆蓋父級中的具有相同名稱和屬性源名稱的屬性。

3.修改Bootstrap配置文件的位置

bootstrap.yml的位置可以通過在配置屬性中設置spring.cloud.bootstrap.name(默認是bootstrap)或者spring.cloud.bootstrap.location來修改。

4.重載遠程屬性

通過Bootstrap上下文添加到應用程序的屬性源通常是遠程的,例如來自配置中心,通常本地的配置文件不能覆蓋這些遠程屬性源。一般來說過,啟動命令行參數的優先級高于遠程配置,可以通過設定啟動命令行參數的方式覆蓋遠程配置。

如果想使用應用程序的系統屬性或者配置文件覆蓋遠程屬性,那么遠程屬性源必須設置為spring.cloud.config.allowOverride=true(這個配置在本地設置不會生效)。在遠程屬性源中設定上述配置后,就可以通過更為細粒度的設置來控制遠程屬性是否能被重載,具體配置如下所示。

        spring:
            cloud:
                config:
                    overrideNone: true #本地屬性覆蓋所有的遠程屬性源
                    overrideSystemProperties: false#僅覆蓋遠程屬性源中的系統屬性和環境變量

5.自定義Bootstrap配置

自定義Bootstrap配置過程與Spring Boot自動配置運行原理類似,具體操作是在/META-INF/spring.factories文件中添加org.springframework.cloud.bootstrap.BootstrapConfiguration配置項。配置項的值是一系列用來創建Context的@Configuration配置類,配置類之間以逗號分隔。這些類可以為應用上下文提供Bean實例,配置類可以通過標記@Order來控制Bean實例初始化序列。如下例所示,在引導過程中添加了一個LogAutoConfiguration的配置類,為應用程序添加日志相關的Bean實例:

        org.springframework.cloud.bootstrap.BootstrapConfiguration=\
            com.demo.starter.config.LogAutoConfiguration

6.自定義Bootstrap屬性源

默認的Bootstrap外部配置屬性源是Spring Cloud Config Server,即使用配置中心加載外部屬性。但是用戶也可以通過將PropertySourceLocator類型的Bean實例添加到Bootstrap上下文(在spring.factories添加對應的配置類)來添加額外的屬性來源。通過這種方法可以從不同的服務器或者數據庫中加載額外的屬性,如下所示:

        @Configuration
        public class CustomPropertySourceLocator implements PropertySourceLocator {
            @Override
            public PropertySource<? > locate(Environment environment){
                return new MapPropertySource("customProperty",
                    Collections.<String, Object>singletonMap("property.from.sample.custom.
                        source", "worked as intended"));
            }
        }

上述代碼中傳入的Environment參數用于創建應用上下文,它具有Spring Boot提供的屬性源,可以使用它們來加載特定的屬性源(例如重新設置spring.application.name)。可以在META-INF/spring.factories文件中添加如下記錄來配置屬性源:

        org.springframework.cloud.bootstrap.BootstrapConfiguration=\
            sample.custom.CustomPropertySourceLocator

上述配置令應用程序可以使用CustomPropertySourceLocator作為其屬性源。

7. Environment變化

Config Client應用程序會監聽EnvironmentChangeEvent事件,當監聽到一個EnvironmentChangeEvent時,它將持有一個被改變的鍵值對列表,應用程序使用這些值來:□ 重新綁定所有的@ConfigurationProperties的Bean實例,更新本地的配置屬性。

□ 為在logging.level.*的所有屬性設置日志的等級。

一般來講,Config Client默認不會使用輪詢方法來監聽Environment中的改變。在Spring Cloud中,Spring Cloud Config Server使用Spring Cloud Bus將EnvironmentChangeEvent廣播到所有的Config Client中,通知它們Environment發生變化。

EnvironmentChangeEvent是一個事件類,用于在Environment發生修改時發布事件。開發者可以通過訪問/configprops端點(常規的Spring Boot Actuator端點)來驗證這些更改是否綁定到@ConfigurationProperties的Bean實例上。例如一個DataSource的最大連接數量在運行時被改變了(DataSource默認由Spring Boot創建,屬于@ConfigurationProperties的Bean)并且動態增加容量,可以通過查看Config Client應用程序的/configprops端點來驗證DataSource的最大連接池數量是否發生變化。

8.刷新范圍

一個被標記為@RefreshScope的Spring Bean實例在配置發生變更時可以重新進行初始化,即動態刷新配置,這是為了解決狀態Bean實例只能在初始化的時候才能進行屬性注入的問題。

被@RefreshScope修飾的Bean實例是懶加載的,即當它們被使用的時候才會進行初始化(方法被調用的時候),想要在下次方法調用前強制重新初始化一個Bean實例,只需要將它的緩存失效即可。

RefreshScope是上下文中的一個Bean實例,它有一個公共方法refreshAll,該方法可以通過清除目標緩存來刷新作用域中的所有Bean實例。RefreshScope也有一個refresh方法來按照名字刷新單個Bean。

2.2.2 Spring Cloud Commons:公共抽象

Spring Cloud將服務發現、負載均衡和斷路器等通用模型封裝在一個公共抽象中,可以被所有的Spring Cloud客戶端使用,不依賴于具體的實現(例如服務發現就有Eureka和Consul等不同的實現),這些公共抽象位于Spring Cloud Commons項目中。

1. @EnableDiscoveryClient注解

@EnableDiscoveryClient注解用于在META-INF/spring.factories文件中查找DiscoveryClient(DiscoveryClient為服務發現功能抽象類)的實現。spring.factories文件的org.springframework. cloud.client.discovery.EnableDiscoveryClient配置項可以指定DiscoveryClient的實現類。DiscoveryClient目前的實現有Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery和Spring Cloud Zookeeper Discovery。

DiscoveryClient的實現類會自動將本地的Spring Boot服務注冊到遠程服務發現中心。可以通過在@EnableDiscoveryClient中設置autoRegister=false來禁止自動注冊行為。

在Finchley版本的Spring Cloud中,不需要顯式使用@EnableDiscoveryClient來開啟客戶端的服務注冊與發現功能。只要在類路徑中,有DiscoveryClient的實現就能使Spring Cloud應用注冊到服務發現中心。

2.服務注冊(ServiceRegistry)

Spring Cloud Commons的ServiceRegister接口提供register(服務注冊)和deregister(服務下線)方法,使開發者可以自定義注冊服務的邏輯,如下所示:

          public interface ServiceRegistry<R extends Registration> {
              void register(R registration);
              void deregister(R registration);
          }

每一個ServiceRegistry的實現都擁有自己的注冊表實現,如Eureka、Consul等。

3. RestTemplate的負載均衡

創建RestTemplate實例的時候,使用@LoadBalanced注解可以將RestTemplate自動配置為使用負載均衡的狀態。@LoadBalanced將使用Ribbon為RestTemplate執行負載均衡策略。

創建負載均衡的RestTemplate不再能通過自動配置來創建,必須通過配置類創建,具體實例如下所示:

          @Configuration
          public class MyConfiguration {
 
              @LoadBalanced
              @Bean
              RestTemplate restTemplate(){
                  return new RestTemplate();
              }
          }
 
          public class MyApplication {
              @Autowired
              private RestTemplate restTemplate;
 
              public String getMyApplicationName(){
                  //使用restTemplate訪問my-application微服務的/name接口
                    String  name  =  restTemplate.getForObject("http://my-application/name",
                        String.class);
                  return name;
              }
          }

URI需要使用服務名來指定需要訪問應用服務,Ribbon客戶端將通過服務名從服務發現應用處獲取具體的服務地址來創建一個完整的網絡地址,以實現網絡調用。

4. RestTemplate的失敗重試

負載均衡的RestTemplate可以添加失敗重試機制。默認情況下,失敗重試機制是關閉的,啟用方式是將Spring Retry添加到應用程序的類路徑中。還可以設置spring.cloud. loadbalancer.retry.enabled=false禁止類路徑中Spring retry的重試邏輯。

如果想要添加一個或者多個RetryListener到重試請求中,可以創建一個類型為LoadBalancedRetryListenerFactory的Bean,用來返回將要用于重試機制的RetryListener的列表,如下代碼所示:

        @Configuration
        public class RryListenerConfiguration {
            @Bean
            LoadBalancedRetryListenerFactory retryListenerFactory(){
                return new LoadBalancedRetryListenerFactory(){
                    @Override
                    public RetryListener[] createRetryListeners(String service){
                        return new RetryListener[]{new RetryListener(){
                            @Override
                            // 重試開始前的工作
                            public  <T,  E  extends  Throwable>  boolean  open(RetryContext
                                  context, RetryCallback<T, E> callback){
                                  return true;
                            }
                            // 重試結束后的工作
                            @Override
                              public  <T,  E  extends  Throwable>  void  close(RetryContext
                                  context, RetryCallback<T, E> callback, Throwable throwable){
                            }
                            // 重試出錯后的工作
                            @Override
                            public  <T,  E  extends  Throwable>  void  onError(RetryContext
                                  context, RetryCallback<T, E> callback, Throwable throwable){
                            }
                        }};
                    }
                };
            }
        }

其中,自定義配置類中定義了生成LoadBalancedRetryListenerFactory實例的@Bean方法,該工廠類的createRetryListeners方法會生成一個RetryListener實例,用于進行網絡請求的重試。

主站蜘蛛池模板: 长葛市| 德化县| 扬州市| 丘北县| 夏河县| 文山县| 田东县| 仪征市| 文山县| 苏尼特右旗| 弋阳县| 堆龙德庆县| 平凉市| 永兴县| 南投市| 云霄县| 剑阁县| 英德市| 吉木乃县| 岳阳市| 枣阳市| 玉屏| 龙山县| 凤山县| 乌什县| 和平县| 独山县| 饶平县| 祁阳县| 衡南县| 常州市| 石台县| 柏乡县| 房山区| 奉新县| 黔西县| 长乐市| 遂平县| 通河县| 贡山| 武义县|