spring cloud gateway集成hystrix
本文主要研究一下spring cloud gateway如何集成hystrix
maven
1 2 3 4 |
< dependency > < groupId >org.springframework.cloud</ groupId > < artifactId >spring-cloud-starter-netflix-hystrix</ artifactId > </ dependency > |
添加spring-cloud-starter-netflix-hystrix依赖,开启hystrix
配置实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
hystrix测试数据mand.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 |
首先filter里头配置了name为Hystrix的filter,实际是对应HystrixGatewayFilterFactory 然后指定了hystrix command的名称,及fallbackUri,注意fallbackUri要以forward开头 最后通过hystrix测试数据mand.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds指定该command的超时时间
fallback实例
1 2 3 4 5 6 7 8 |
@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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@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类库,就有HystrixObservableCommand.class, RxReactiveStreams.class,便开启HystrixConfiguration
HystrixGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/factory/HystrixGatewayFilterFactory.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/** * 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(); }; } //...... } |
这里创建了RouteHystrixCommand,将其转换为Mono,然后在onErrorResume的时候判断如果HystrixRuntimeException的failureType是FailureType.TIMEOUT类型的话,则返回GATEWAY_TIMEOUT(504, "Gateway Timeout")状态码。
RouteHystrixCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
//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)); } } |
这里重写了construct方法,RxReactiveStreams.toObservable(this.chain.filter(exchange)),将reactor的Mono转换为rxjava的Observable 这里重写了resumeWithFallback方法,针对有fallbackUri的情况,重新路由到fallbackUri的地址
Config
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
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校验了fallbackUri,如果不为null,则必须以forward开头
小结
spring cloud gateway集成hystrix,分为如下几步:
添加spring-cloud-starter-netflix-hystrix依赖 在对应route的filter添加name为Hystrix的filter,同时指定hystrix command的名称,及其fallbackUri(可选) 指定该hystrix command的超时时间等。以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
原文链接:https://HdhCmsTestjianshu测试数据/p/81b0059dbd98
查看更多关于spring cloud gateway集成hystrix实战篇的详细内容...