3. Spring Cloud Commons: 公共抽象
諸如服務發現,負載均衡和斷路器之類的模式适用于所有Spring Cloud用戶端可以使用的公共抽象層,與實作無關(例如,使用Eureka或Consul發現)。
3.1 @EnableDiscoveryClient
Spring Cloud Commons 提供 @EnableDiscoveryClient 注解。這使用META-INF/spring.factories查找DiscoveryClient接口的實作。Discovery Client 的實作添加配置類至spring.factories下的org.springframework.cloud.client.discovery.EnableDiscoveryClient 鍵。DiscoveryClient的例子包括Spring Cloud Netflix Eureka,Spring Cloud Consul Discovery和Spring Cloud Zookeeper Discovery。
預設情況下,DiscoveryClient的實作會使用遠端發現服務自動注冊本地Spring Boot伺服器。可以通過在@EnableDiscoveryClient 中設定autoRegister=false 來禁用此行為。
@EnableDiscoveryClient 不再是必須的。你可以在類路徑下放置DiscoveryClient實作以使Spring Boot應用程式向服務發現伺服器注冊。
3.1.1 健康訓示器
Commons建立了一個Spring Boot HealthIndicator,DiscoveryClient實作可以通過實作DiscoveryHealthIndicator來參與。 要禁用複合HealthIndicator,請設定spring.cloud.discovery.client.composite-indicator.enabled = false。 基于DiscoveryClient的通用HealthIndicator是自動配置的(DiscoveryClientHealthIndicator)。 要禁用它,請設定spring.cloud.discovery.client.health-indicator.enabled = false。 要禁用DiscoveryClientHealthIndicator的description字段,請設定spring.cloud.discovery.client.health-indicator.include-description = false。 否則,它可能會像卷起的HealthIndicator的描述一樣冒出來。
3.2 服務注冊
Commons現在提供ServiceRegistry接口,該接口提供諸如注冊(注冊)和登出(注冊)之類的方法,這些方法允許您提供自定義注冊服務。 Registration是标記接口。
以下示例顯示正在使用的ServiceRegistry:
@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
private ServiceRegistry registry;
public MyConfiguration(ServiceRegistry registry) {
this.registry = registry;
}
// called through some external process, such as an event or a custom actuator endpoint
public void register() {
Registration registration = constructRegistration();
this.registry.register(registration);
}
}
每個ServiceRegistry實作都有自己的Registry實作。
·ZookeeperRegistration與ZookeeperServiceRegistry一起使用
·EurekaRegistration與EurekaServiceRegistry使用
·ConsulRegistration與ConsulRegistry一起使用
如果你使用的是ServiceRegistry接口,則需有為正在使用的ServiceRegistry實作傳遞正确的Registry實作。
3.2.1 ServiceRegistry 自動注冊
預設情況下,ServiceRegistry 自動注冊正在運作的服務。要禁止該行為,你可以設定:*@EnableDiscoveryClient(autoRegister=false)來永久禁止自動注冊。通過配置*.spring.cloud.service-registry.auto-registration.enabled=false 禁止該行為。
ServiceRegistry 自動注冊事件
當服務自動注冊時,将觸發兩個事件。 第一個事件名為InstancePreRegisteredEvent,在注冊服務之前觸發。 第二個事件名為InstanceRegisteredEvent,在注冊服務後觸發。 您可以注冊一個ApplicationListener來監聽并響應這些事件。
·如果spring.cloud.service-registry.auto-registration.enabled設定為false,則不會觸發這些事件。
3.2.2 服務注冊執行器端點
Spring Cloud Commons 提供 /Service-registry 執行器端點。此端點依賴于Spring Application Context中的Registration bean。使用GET調用/service-registry傳回注冊的狀态。使用POST和JSON體調用相同的端點更改目前注冊的狀态為新的值。JSON體必須包含預期值的狀态字段。關于在更新狀态時的允許值和狀态傳回值請參考所使用的ServiceRegistry實作的文檔。例如,Eureka已支援的狀态是UP,DOWN,OUT_OF_SERVICE 和 UNKNOWN.
3.3 Spring RestTemplate 作為負載均衡用戶端
RestTemplate 可以自動配置為使用ribbon。要建立負載均衡的RestTemplate,請建立RestTemplate @Bean 并使用@LoadBalanced 限定符,如以下例子所示:
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
public String doOtherStuff() {
String results = restTemplate.getForObject("http://stores/stores", String.class);
return results;
}
}
警告:RestTemplate不再通過自動配置建立。個人應用程式必須自己建立。
URL需要使用虛拟主機名(即服務名稱,而不是主機名)。Ribbon用戶端用于建立完整的實體位址。有關如何設定RestTemplate的詳細資訊,請參考RibbonAutoConfiguration。
3.4 Spring WebClient 作為負載均衡用戶端
WebClient 可以自動配置為使用LoadBalancerClient。要建立負載均衡的WebClient,請建立WebClient.Builder @Bean 并且使用@LoadBalanced限定符,如以下例子所示:
@Configuration
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
public Mono<String> doOtherStuff() {
return webClientBuilder.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
}
URL需要使用虛拟主機名(即服務名稱,而不是主機名)。Ribbon用戶端用于建立完整的實體位址。
3.4.1 重試失敗請求
負載均衡的RestTemplate可以配置重試失敗請求。預設情況下,該邏輯是禁止的。你可以通過添加Spring Retry到你的應用程式的類路徑下來啟用它。負載均衡的RestTemplate擁有與重試失敗請求相關的一些Rinbbon配置值。你可以使用client.ribbon.MaxAutoRetries,client.ribbon.MaxAutoRetriesNextServer 與 client.ribbon.OkToRetryOnAllOperations 屬性。如果你想使用類路徑上的Spring Retry 來禁用重試邏輯,可以設定 spring.cloud.loadbalancer.retry.retry.enabled=false。有關這些屬性的說明,請參考Ribbon文檔。
如果要在重試中實作BackOffPolicy,需要建立LoadBalancedRetryFactory類型的bean并覆寫createBackOffPolicy方法:
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
前面的例子中的client應該替換為Ribbon用戶端的名稱。
如果要将一個或多個RetryListener實作添加到重試功能,需要建立類型為LoadBalancedRetryListenerFactory的bean,并傳回要用于給定服務的RetryListener數組,如以下例子所示:
@Configuration
public class MyConfiguration {
@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) {
//TODO Do you business...
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
}};
}
};
}
}
3.5 多個RestTemplate 對象
如果你想建立一個非負載均衡的RestTemplate,則建立一個RestTemplate bean 并注入它。要通路負載均衡的RestTemplate,請在建立@Bean與使用@LoadBalanced 限定符,如以下例子所示:
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate loadBalanced() {
return new RestTemplate();
}
@Primary
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
@Autowired
@LoadBalanced
private RestTemplate loadBalanced;
public String doOtherStuff() {
return loadBalanced.getForObject("http://stores/stores", String.class);
}
public String doStuff() {
return restTemplate.getForObject("http://example.com", String.class);
}
}
重要:請注意前面示例中的普通RestTemplate聲明中使用@Primary注解來消除無限定@Autowired注入的歧義
如果你遇到諸如java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89 的錯誤,嘗試注入 RestOperations或設定spring.aop.proxyTargetClass=true。
3.6 Spring WebFlux WebClient 作為負載均衡用戶端
WebClient 可以配置為使用 LoadBalancerClient。如果spring-webflux在類路徑上LoadBalancerExchangeFilterFunction是自動配置的。以下例子顯示如何配置WebClient以使用負載均衡器:
public class MyClass {
@Autowired
private LoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URL需要使用虛拟主機名(即服務名稱,而不是主機名)。LoadBalancerClient用于建立完整的實體位址。
3.7 忽略網絡接口
有時忽略某些命名的網絡接口是有用的,這樣它們就可以從服務發現注冊中删除(例如,在docker容器中運作時)。 可以設定正規表達式清單來會略指定的網絡接口。 以下配置忽略docker0接口和以veth開頭的所有接口:
application.yml.
spring:
cloud:
inetutils:
ignoredInterfaces:
- docker0
- veth.*
你也可以使用正規表達式清單來限制指定網絡位址,如以下示例所示:
bootstrap.yml.
spring:
cloud:
inetutils:
preferredNetworks:
- 192.168
- 10.0
你也可以限制使用本地站點位址,如以下示例所示:
application.yml.
spring:
cloud:
inetutils:
useOnlySiteLocalInterfaces: true
有關建構站點本地位址的詳細資訊,請參考Inet4Address.html.isSiteLocalAddress()。
3.8 HTTP 用戶端工廠
Spring Cloud Commons 為建立Apache HTTP用戶端(ApacheHttppClientFactory)和OK HTTP用戶端(OkHttpClientFactory)提供bean。隻有OK HTTP jar 在了路徑上才會建立OkHttpClientFactory bean。另外,Spring Cloud Commons 為建立兩個用戶端使用的連接配接管理器提供bean:對應Apache HTTP用戶端的ApacheHttpClientConnectionMannagerFactory和對應OK HTTP用戶端的OkHttpClientConnectionPoolFactory。如果要自定義在下遊項目中HTTP用戶端的建立方式,可以提供自己的這些bean實作。另外,你可以提供類型為HttpClientBuilder或OkHttpClient.Builder的bean,預設工廠使用這些建構器作為傳回下遊工程的建構器的基礎。你也可以通過設定spring.cloud.httpclientfactories,apache.enabled 或 spring.cloud.httpclientfactories.ok.enabled 為false來禁用這些bean的建立。
2.9 啟用特性
Spring Cloud Commons 提供 /features 執行器端點。該端點傳回類路徑上可用的特性以及它們是否啟用。傳回的資訊包含特性類型,名稱,版本和供應商。
3.9.1 特性類型
有兩種類型的‘特性’:抽象和命名。
抽象特性是接口或抽象類定義和實作建立所在的特性(總覺的哪裡怪怪的,原文:Abstract features are features where an interface or abstract class is defined and that an implementation the creates),如 DiscoveryClient,LoadBalancerClient 或LockService。抽象類或接口用于查找上下文中對應類型的bean。顯示的版本是bean.getClass().getPackage().getImplementionVersion()。
命名特性是它們所實作的沒有特定類的特性,諸如 "Circuit Breaker", "API Gateway", "Spring Cloud Bus", 和其他。這些特性需要名稱和bean類型。
3.9.2 聲明特性
任何子產品都可以聲明任意數量的HasFeature bean,如以下例子所示:
@Bean
public HasFeatures commonsFeatures() {
return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
}
@Bean
public HasFeatures consulFeatures() {
return HasFeatures.namedFeatures(
new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
}
@Bean
HasFeatures localFeatures() {
return HasFeatures.builder()
.abstractFeature(Foo.class)
.namedFeature(new NamedFeature("Bar Feature", Bar.class))
.abstractFeature(Baz.class)
.build();
}
這些bean中的每一個都應該處于适當的保護@Configuration。
Part I. Cloud Native Applications 完!to be continued ······