spring cloud gateway集成hystrix實(shí)戰(zhàn)篇
spring cloud gateway集成hystrix
本文主要研究一下spring cloud gateway如何集成hystrix
maven
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
添加spring-cloud-starter-netflix-hystrix依賴,開(kāi)啟hystrix
配置實(shí)例
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000 spring: cloud: gateway: discovery: locator: enabled: true routes: - id: employee-service uri: lb://employee-service predicates: - Path=/employee/** filters: - RewritePath=/employee/(?<path>.*), /$\{path} - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback
- 首先f(wàn)ilter里頭配置了name為Hystrix的filter,實(shí)際是對(duì)應(yīng)HystrixGatewayFilterFactory
- 然后指定了hystrix command的名稱,及fallbackUri,注意fallbackUri要以forward開(kāi)頭
- 最后通過(guò)hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds指定該command的超時(shí)時(shí)間
fallback實(shí)例
@RestController @RequestMapping("/fallback") public class FallbackController { @RequestMapping("") public String fallback(){ return "error"; } }
源碼解析
GatewayAutoConfiguration
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
@Configuration @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) @EnableConfigurationProperties @AutoConfigureBefore(HttpHandlerAutoConfiguration.class) @AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class}) @ConditionalOnClass(DispatcherHandler.class) public class GatewayAutoConfiguration { //...... @Configuration @ConditionalOnClass({HystrixObservableCommand.class, RxReactiveStreams.class}) protected static class HystrixConfiguration { @Bean public HystrixGatewayFilterFactory hystrixGatewayFilterFactory(DispatcherHandler dispatcherHandler) { return new HystrixGatewayFilterFactory(dispatcherHandler); } } //...... }
引入spring-cloud-starter-netflix-hystrix類庫(kù),就有HystrixObservableCommand.class, RxReactiveStreams.class,便開(kāi)啟HystrixConfiguration
HystrixGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/HystrixGatewayFilterFactory.java
/** * Depends on `spring-cloud-starter-netflix-hystrix`, {@see http://cloud.spring.io/spring-cloud-netflix/} * @author Spencer Gibb */ public class HystrixGatewayFilterFactory extends AbstractGatewayFilterFactory<HystrixGatewayFilterFactory.Config> { public static final String FALLBACK_URI = "fallbackUri"; private final DispatcherHandler dispatcherHandler; public HystrixGatewayFilterFactory(DispatcherHandler dispatcherHandler) { super(Config.class); this.dispatcherHandler = dispatcherHandler; } @Override public List<String> shortcutFieldOrder() { return Arrays.asList(NAME_KEY); } public GatewayFilter apply(String routeId, Consumer<Config> consumer) { Config config = newConfig(); consumer.accept(config); if (StringUtils.isEmpty(config.getName()) && !StringUtils.isEmpty(routeId)) { config.setName(routeId); } return apply(config); } @Override public GatewayFilter apply(Config config) { //TODO: if no name is supplied, generate one from command id (useful for default filter) if (config.setter == null) { Assert.notNull(config.name, "A name must be supplied for the Hystrix Command Key"); HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName()); HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(config.name); config.setter = Setter.withGroupKey(groupKey) .andCommandKey(commandKey); } return (exchange, chain) -> { RouteHystrixCommand command = new RouteHystrixCommand(config.setter, config.fallbackUri, exchange, chain); return Mono.create(s -> { Subscription sub = command.toObservable().subscribe(s::success, s::error, s::success); s.onCancel(sub::unsubscribe); }).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> { if (throwable instanceof HystrixRuntimeException) { HystrixRuntimeException e = (HystrixRuntimeException) throwable; if (e.getFailureType() == TIMEOUT) { //TODO: optionally set status setResponseStatus(exchange, HttpStatus.GATEWAY_TIMEOUT); return exchange.getResponse().setComplete(); } } return Mono.error(throwable); }).then(); }; } //...... }
這里創(chuàng)建了RouteHystrixCommand,將其轉(zhuǎn)換為Mono,然后在onErrorResume的時(shí)候判斷如果HystrixRuntimeException的failureType是FailureType.TIMEOUT類型的話,則返回GATEWAY_TIMEOUT(504, "Gateway Timeout")狀態(tài)碼。
RouteHystrixCommand
//TODO: replace with HystrixMonoCommand that we write private class RouteHystrixCommand extends HystrixObservableCommand<Void> { private final URI fallbackUri; private final ServerWebExchange exchange; private final GatewayFilterChain chain; RouteHystrixCommand(Setter setter, URI fallbackUri, ServerWebExchange exchange, GatewayFilterChain chain) { super(setter); this.fallbackUri = fallbackUri; this.exchange = exchange; this.chain = chain; } @Override protected Observable<Void> construct() { return RxReactiveStreams.toObservable(this.chain.filter(exchange)); } @Override protected Observable<Void> resumeWithFallback() { if (this.fallbackUri == null) { return super.resumeWithFallback(); } //TODO: copied from RouteToRequestUrlFilter URI uri = exchange.getRequest().getURI(); //TODO: assume always? boolean encoded = containsEncodedParts(uri); URI requestUrl = UriComponentsBuilder.fromUri(uri) .host(null) .port(null) .uri(this.fallbackUri) .build(encoded) .toUri(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl); ServerHttpRequest request = this.exchange.getRequest().mutate().uri(requestUrl).build(); ServerWebExchange mutated = exchange.mutate().request(request).build(); return RxReactiveStreams.toObservable(HystrixGatewayFilterFactory.this.dispatcherHandler.handle(mutated)); } }
- 這里重寫(xiě)了construct方法,RxReactiveStreams.toObservable(this.chain.filter(exchange)),將reactor的Mono轉(zhuǎn)換為rxjava的Observable
- 這里重寫(xiě)了resumeWithFallback方法,針對(duì)有fallbackUri的情況,重新路由到fallbackUri的地址
Config
public static class Config { private String name; private Setter setter; private URI fallbackUri; public String getName() { return name; } public Config setName(String name) { this.name = name; return this; } public Config setFallbackUri(String fallbackUri) { if (fallbackUri != null) { setFallbackUri(URI.create(fallbackUri)); } return this; } public URI getFallbackUri() { return fallbackUri; } public void setFallbackUri(URI fallbackUri) { if (fallbackUri != null && !"forward".equals(fallbackUri.getScheme())) { throw new IllegalArgumentException("Hystrix Filter currently only supports 'forward' URIs, found " + fallbackUri); } this.fallbackUri = fallbackUri; } public Config setSetter(Setter setter) { this.setter = setter; return this; } }
可以看到Config校驗(yàn)了fallbackUri,如果不為null,則必須以forward開(kāi)頭
小結(jié)
spring cloud gateway集成hystrix,分為如下幾步:
- 添加spring-cloud-starter-netflix-hystrix依賴
- 在對(duì)應(yīng)route的filter添加name為Hystrix的filter,同時(shí)指定hystrix command的名稱,及其fallbackUri(可選)
- 指定該hystrix command的超時(shí)時(shí)間等。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于java開(kāi)發(fā)之系統(tǒng)托盤(pán)的應(yīng)用
本篇文章介紹了,基于java開(kāi)發(fā)之系統(tǒng)托盤(pán)的應(yīng)用。需要的朋友參考下2013-05-05Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解
在開(kāi)發(fā)中,參數(shù)傳遞是必不可少的一個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于Spring Mvc中傳遞參數(shù)方法之url/requestMapping的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-07-07Java中String和StringBuffer及StringBuilder?有什么區(qū)別
這篇文章主要介紹了Java中String和StringBuffer及StringBuilder?有什么區(qū)別,String?是?Java?語(yǔ)言非?;A(chǔ)和重要的類,更多相關(guān)內(nèi)容需要的小伙伴可以參考下面文章內(nèi)容2022-06-06Java動(dòng)態(tài)代理Proxy應(yīng)用和底層源碼詳細(xì)分析
Java動(dòng)態(tài)代理是一種在運(yùn)行時(shí)生成代理類的機(jī)制,用于代替手動(dòng)編寫(xiě)代理類的過(guò)程,這篇文章主要給大家介紹了關(guān)于Java動(dòng)態(tài)代理Proxy應(yīng)用和底層源碼詳細(xì)分析的相關(guān)資料,需要的朋友可以參考下2024-03-03java版微信公眾平臺(tái)消息接口應(yīng)用示例
這篇文章主要介紹了java版微信公眾平臺(tái)消息接口應(yīng)用,結(jié)合實(shí)例形式對(duì)比分析了PHP與java應(yīng)用微信公眾平臺(tái)接口的相關(guān)調(diào)用與操作技巧,需要的朋友可以參考下2017-07-07SpringBoot+MySQL+Jpa實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的增刪改查和分頁(yè)詳解
這篇文章主要介紹了SpringBoot+MySQL+Jpa實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)的增刪改查和分頁(yè)詳解,需要的朋友可以參考下2020-02-02