spring|spring cloud gateway集成hystrix实战篇
spring cloud gateway集成hystrix
本文主要研究一下spring cloud gateway如何集成hystrix
maven
org.springframework.cloud spring-cloud-starter-netflix-hystrix
添加spring-cloud-starter-netflix-hystrix依赖,开启hystrix
配置实例
hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000spring:cloud:gateway:discovery:locator:enabled: trueroutes:- id: employee-serviceuri: lb://employee-servicepredicates:- Path=/employee/**filters:- RewritePath=/employee/(?.*), /$\{path}- name: Hystrixargs:name: fallbackcmdfallbackUri: forward:/fallback
- 首先filter里头配置了name为Hystrix的filter,实际是对应HystrixGatewayFilterFactory
- 然后指定了hystrix command的名称,及fallbackUri,注意fallbackUri要以forward开头
- 最后通过hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds指定该command的超时时间
@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 {@Beanpublic 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 {public static final String FALLBACK_URI = "fallbackUri"; private final DispatcherHandler dispatcherHandler; public HystrixGatewayFilterFactory(DispatcherHandler dispatcherHandler) {super(Config.class); this.dispatcherHandler = dispatcherHandler; }@Overridepublic List shortcutFieldOrder() {return Arrays.asList(NAME_KEY); }public GatewayFilter apply(String routeId, Consumerconsumer) {Config config = newConfig(); consumer.accept(config); if (StringUtils.isEmpty(config.getName()) && !StringUtils.isEmpty(routeId)) {config.setName(routeId); }return apply(config); }@Overridepublic 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 -> {if (throwable instanceof HystrixRuntimeException) {HystrixRuntimeException e = (HystrixRuntimeException) throwable; if (e.getFailureType() == TIMEOUT) { //TODO: optionally set statussetResponseStatus(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 writeprivate class RouteHystrixCommand extends HystrixObservableCommand{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; }@Overrideprotected Observable construct() {return RxReactiveStreams.toObservable(this.chain.filter(exchange)); }@Overrideprotected Observable resumeWithFallback() {if (this.fallbackUri == null) {return super.resumeWithFallback(); }//TODO: copied from RouteToRequestUrlFilterURI 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的地址
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的超时时间等。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- Spring|Spring Boot之ImportSelector