spring cloud gateway集成hystrix实战篇
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依赖,开启hystrix
配置实例
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
- 首先filter里头配置了name为hystrix的filter,实际是对应hystrixgatewayfilterfactory
- 然后指定了hystrix command的名称,及fallbackuri,注意fallbackuri要以forward开头
- 最后通过hystrix.command.fallbackcmd.execution.isolation.thread.timeoutinmilliseconds指定该command的超时时间
fallback实例
@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类库,就有hystrixobservablecommand.class, rxreactivestreams.class,便开启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(); }; } //...... }
这里创建了routehystrixcommand,将其转换为mono,然后在onerrorresume的时候判断如果hystrixruntimeexception的failuretype是failuretype.timeout类型的话,则返回gateway_timeout(504, "gateway timeout")状态码。
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)); } }
- 这里重写了construct方法,rxreactivestreams.toobservable(this.chain.filter(exchange)),将reactor的mono转换为rxjava的observable
- 这里重写了resumewithfallback方法,针对有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校验了fallbackuri,如果不为null,则必须以forward开头
小结
spring cloud gateway集成hystrix,分为如下几步:
- 添加spring-cloud-starter-netflix-hystrix依赖
- 在对应route的filter添加name为hystrix的filter,同时指定hystrix command的名称,及其fallbackuri(可选)
- 指定该hystrix command的超时时间等。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: 猪腰如何切薄片
推荐阅读
-
Spring Cloud系列-Zuul网关集成JWT身份验证
-
跟我学SpringCloud | 第十四篇:Spring Cloud Gateway高级应用
-
Spring Cloud第六篇 | Hystrix仪表盘监控Hystrix Dashboard
-
Spring Cloud第五篇 | 服务熔断Hystrix
-
记录spring-cloud-gateway获取post请求body参数,以及后端服务处理后的响应参数过程 gateway:2.2.0.RELEASE
-
玩转Spring Cloud之熔断降级(Hystrix)与监控
-
Spring Cloud Greenwich 正式发布,Hystrix 即将寿终正寝。。
-
Nacos+Spring Cloud Gateway动态路由配置
-
Spring Cloud实战之初级入门(四)— 利用Hystrix实现服务熔断与服务监控
-
Spring Cloud Hystrix异常处理方法详解