使用springcloud gateway搭建网关(分流,限流,熔断)
Spring Cloud Gateway
Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。
Spring Cloud Gateway 作為 Spring Cloud 生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標是替代 Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全,監(jiān)控/指標,和限流。
相關(guān)概念:
- Route(路由):這是網(wǎng)關(guān)的基本構(gòu)建塊。它由一個 ID,一個目標 URI,一組斷言和一組過濾器定義。如果斷言為真,則路由匹配。
- Predicate(斷言):這是一個 Java 8 的 Predicate。輸入類型是一個 ServerWebExchange。我們可以使用它來匹配來自 HTTP 請求的任何內(nèi)容,例如 headers 或參數(shù)。
- Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的實例,我們可以使用它修改請求和響應(yīng)。
工作流程:
客戶端向 Spring Cloud Gateway 發(fā)出請求。如果 Gateway Handler Mapping 中找到與請求相匹配的路由,將其發(fā)送到 Gateway Web Handler。Handler 再通過指定的過濾器鏈來將請求發(fā)送到我們實際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。 過濾器之間用虛線分開是因為過濾器可能會在發(fā)送代理請求之前(“pre”)或之后(“post”)執(zhí)行業(yè)務(wù)邏輯。
Spring Cloud Gateway 的特征:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 動態(tài)路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 斷路器
- 集成 Spring Cloud DiscoveryClient
- 易于編寫的 Predicates 和 Filters
- 限流
- 路徑重寫
?快速上手
引入spring-boot??2.1.1.RELEASE ,springcloud的版本為?Greenwich.M3
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>1.8</java.version><spring-cloud.version>Greenwich.M3</spring-cloud.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>?添加的依賴包如下
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId></dependency>?注意springcloud gateway使用的web框架為webflux,和springMVC不兼容。引入的限流組件是hystrix。redis底層不再使用jedis,而是lettuce。
路由斷言
?接下來就是配置了,可以使用java代碼硬編碼配置路由過濾器,也可以使用yml配置文件配置。下面我們首先介紹配置文件配置方式
application.yml
server.port: 8082spring:application:name: gatewaycloud:gateway:routes:- id: path_routeuri: http://localhost:8000order: 0predicates:- Path=/foo/**filters:- StripPrefix=1?上面給出了一個根據(jù)請求路徑來匹配目標uri的例子,如果請求的路徑為/foo/bar,則目標uri為?http://localhost:8000/bar。如果上面例子中沒有加一個StripPrefix=1過濾器,則目標uri 為http://localhost:8000/foo/bar,StripPrefix過濾器是去掉一個路徑。
?其他的路由斷言和過濾器使用方法請查看官網(wǎng)
?https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RC2/single/spring-cloud-gateway.html#gateway-how-it-works
?接下來我們來看一下設(shè)計一個網(wǎng)關(guān)應(yīng)該需要的一些功能
修改接口返回報文
因為網(wǎng)關(guān)路由的接口返回報文格式各異,并且網(wǎng)關(guān)也有有一些限流、認證、熔斷降級的返回報文,為了統(tǒng)一這些報文的返回格式,網(wǎng)關(guān)必須要對接口的返回報文進行修改,過濾器代碼如下:
package org.gateway.filter.global;import java.nio.charset.Charset;import org.gateway.response.Response; import org.reactivestreams.Publisher; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange;import com.alibaba.fastjson.JSON;import reactor.core.publisher.Flux; import reactor.core.publisher.Mono;@Component public class WrapperResponseFilter implements GlobalFilter, Ordered {@Overridepublic int getOrder() {// -1 is response write filter, must be called before thatreturn -2;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpResponse originalResponse = exchange.getResponse();DataBufferFactory bufferFactory = originalResponse.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (body instanceof Flux) {Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;return super.writeWith(fluxBody.map(dataBuffer -> {// probably should reuse buffersbyte[] content = new byte[dataBuffer.readableByteCount()];dataBuffer.read(content);// 釋放掉內(nèi)存 DataBufferUtils.release(dataBuffer);String rs = new String(content, Charset.forName("UTF-8"));Response response = new Response();response.setCode("1");response.setMessage("請求成功");response.setData(rs);byte[] newRs = JSON.toJSONString(response).getBytes(Charset.forName("UTF-8"));originalResponse.getHeaders().setContentLength(newRs.length);//如果不重新設(shè)置長度則收不到消息。return bufferFactory.wrap(newRs);}));}// if body is not a flux. never got there.return super.writeWith(body);}};// replace response with decoratorreturn chain.filter(exchange.mutate().response(decoratedResponse).build());} }?
需要注意的是order需要小于-1,需要先于NettyWriteResponseFilter過濾器執(zhí)行。
有了一個這樣的過濾器,我們就可以統(tǒng)一返回報文格式了。
認證
以下提供一個簡單的認證過濾器
package org.gateway.filter.global;import java.nio.charset.StandardCharsets;import org.gateway.response.Response; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange;import com.alibaba.fastjson.JSON;import reactor.core.publisher.Mono;@Component public class AuthFilter implements GlobalFilter{@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String token = exchange.getRequest().getHeaders().getFirst("token");if ("token".equals(token)) {return chain.filter(exchange);}ServerHttpResponse response = exchange.getResponse();Response data = new Response();data.setCode("401");data.setMessage("非法請求");byte[] datas = JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8);DataBuffer buffer = response.bufferFactory().wrap(datas);response.setStatusCode(HttpStatus.UNAUTHORIZED);response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return response.writeWith(Mono.just(buffer));} }?
限流
springcloud gateway 為我們提供了限流過濾器RequestRateLimiterGatewayFilterFactory,和限流的實現(xiàn)類RedisRateLimiter使用令牌桶限流。但是官方的不一定滿足我們的需求,所以我們重新寫一個過濾器(基本和官方一致),只是將官方的返回報文改了。
package org.gateway.limiter;import java.nio.charset.StandardCharsets; import java.util.Map;import org.gateway.response.Response; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse;import com.alibaba.fastjson.JSON;import reactor.core.publisher.Mono;/*** User Request Rate Limiter filter. See https://stripe.com/blog/rate-limiters and*/ public class RateLimiterGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimiterGatewayFilterFactory.Config> {public static final String KEY_RESOLVER_KEY = "keyResolver";private final RateLimiter defaultRateLimiter;private final KeyResolver defaultKeyResolver;public RateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter,KeyResolver defaultKeyResolver) {super(Config.class);this.defaultRateLimiter = defaultRateLimiter;this.defaultKeyResolver = defaultKeyResolver;}public KeyResolver getDefaultKeyResolver() {return defaultKeyResolver;}public RateLimiter getDefaultRateLimiter() {return defaultRateLimiter;}@SuppressWarnings("unchecked")@Overridepublic GatewayFilter apply(Config config) {KeyResolver resolver = (config.keyResolver == null) ? defaultKeyResolver : config.keyResolver;RateLimiter<Object> limiter = (config.rateLimiter == null) ? defaultRateLimiter : config.rateLimiter;return (exchange, chain) -> {Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);return resolver.resolve(exchange).flatMap(key ->// TODO: if key is empty?limiter.isAllowed(route.getId(), key).flatMap(response -> {for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {exchange.getResponse().getHeaders().add(header.getKey(), header.getValue());}if (response.isAllowed()) {return chain.filter(exchange);}ServerHttpResponse rs = exchange.getResponse();Response data = new Response();data.setCode("101");data.setMessage("訪問過快");byte[] datas = JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8);DataBuffer buffer = rs.bufferFactory().wrap(datas);rs.setStatusCode(HttpStatus.UNAUTHORIZED);rs.getHeaders().add("Content-Type", "application/json;charset=UTF-8");return rs.writeWith(Mono.just(buffer));}));};}public static class Config {private KeyResolver keyResolver;private RateLimiter rateLimiter;private HttpStatus statusCode = HttpStatus.TOO_MANY_REQUESTS;public KeyResolver getKeyResolver() {return keyResolver;}public Config setKeyResolver(KeyResolver keyResolver) {this.keyResolver = keyResolver;return this;}public RateLimiter getRateLimiter() {return rateLimiter;}public Config setRateLimiter(RateLimiter rateLimiter) {this.rateLimiter = rateLimiter;return this;}public HttpStatus getStatusCode() {return statusCode;}public Config setStatusCode(HttpStatus statusCode) {this.statusCode = statusCode;return this;}}}?然后限流必須要有一個key,根據(jù)什么來進行限流,ip,接口,或者用戶來進行限流,所以我們自定義一個KeyResolver
package org.gateway.limiter;import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.web.server.ServerWebExchange;import com.alibaba.fastjson.JSON;import reactor.core.publisher.Mono;public class CustomKeyResolver implements KeyResolver {public static final String BEAN_NAME = "customKeyResolver";@Overridepublic Mono<String> resolve(ServerWebExchange exchange) {return Mono.just(getKey(exchange));}/*** * @param exchange* @return*/private String getKey(ServerWebExchange exchange) {LimitKey limitKey = new LimitKey();limitKey.setApi(exchange.getRequest().getPath().toString());limitKey.setBiz(exchange.getRequest().getQueryParams().getFirst("biz"));return JSON.toJSONString(limitKey);} }?最后RedisRateLimiter我們也需要重寫,因為不支持多級限流,原生的只會判斷一個key。代碼如下:
/*** This uses a basic token bucket algorithm and relies on the fact that Redis scripts* execute atomically. No other operations can run between fetching the count and* writing the new count.*/@Overridepublic Mono<Response> isAllowed(String routeId, String id) {if (!this.initialized.get()) {throw new IllegalStateException("RedisRateLimiter is not initialized");}LimitConfig limitConfig = getLimitConfig(routeId);if (limitConfig == null || limitConfig.getTokenConfig().size()==0) {return Mono.just(new Response(true,null));}Map<String, Config> conf = limitConfig.getTokenConfig();LimitKey limitKey = JSON.parseObject(id, LimitKey.class);//api限流String api = limitKey.getApi();Config apiConf = conf.get(api);//業(yè)務(wù)方限流String biz = limitKey.getBiz();Config bizConf = conf.get(biz);if (apiConf!=null) {return isSingleAllow(api,routeId,apiConf).flatMap(res -> {if (res.isAllowed()) {if(bizConf!=null) {return isSingleAllow(biz, routeId, bizConf);}else {return Mono.just(new Response(true,new HashMap<>()));}}else {return Mono.just(res);}} );}else {if (bizConf!=null) {return isSingleAllow(biz, routeId, bizConf);}else {return Mono.just(new Response(true,new HashMap<>()));}}}/*** 單級限流* @param api* @param routeId* @param apiConf* @return */private Mono<Response> isSingleAllow(String key, String routeId, Config config) {// How many requests per second do you want a user to be allowed to do?int replenishRate = config.getReplenishRate();// How much bursting do you want to allow?int burstCapacity = config.getBurstCapacity();try {List<String> keys = getKeys(routeId+"$"+key);// The arguments to the LUA script. time() returns unixtime in seconds.List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",Instant.now().getEpochSecond() + "", "1");// allowed, tokens_left = redis.eval(SCRIPT, keys, args)Flux<List<Long>> flux = this.redisTemplate.execute(this.script, keys, scriptArgs);// .log("redisratelimiter", Level.FINER);return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L))).reduce(new ArrayList<Long>(), (longs, l) -> {longs.addAll(l);return longs;}) .map(results -> {boolean allowed = results.get(0) == 1L;Long tokensLeft = results.get(1);Response response = new Response(allowed, getHeaders(config, tokensLeft));if (log.isDebugEnabled()) {log.debug("response: " + response);}return response;});}catch (Exception e) {/** We don't want a hard dependency on Redis to allow traffic. Make sure to set* an alert so you know if this is happening too much. Stripe's observed* failure rate is 0.01%.*/log.error("Error determining if user allowed from redis", e);}return Mono.just(new Response(true, getHeaders(config, -1L)));}private LimitConfig getLimitConfig(String routeId) {Map<String, LimitConfig> map = new HashMap<>();LimitConfig limitConfig = new LimitConfig();limitConfig.setRouteId("rateLimit_route");Map<String, Config> tokenMap = new HashMap<>();Config apiConfig = new Config();apiConfig.setBurstCapacity(5);apiConfig.setReplenishRate(5);Config bizConfig = new Config();bizConfig.setBurstCapacity(1);bizConfig.setReplenishRate(1);tokenMap.put("/hello/rateLimit", apiConfig);tokenMap.put("jieyin", bizConfig);limitConfig.setTokenConfig(tokenMap);map.put("rateLimit_route", limitConfig);return limitConfig;}?如上的代碼是寫死的,但是我們可以根據(jù)我們的業(yè)務(wù)需求設(shè)計一個自定義key,自定義令牌桶容量和速率的限流規(guī)則。
bean配置和yml配置如下
@Bean@Primarypublic CustomRedisRateLimiter customRedisRateLimiter(ReactiveRedisTemplate<String, String> redisTemplate,@Qualifier(RedisRateLimiter.REDIS_SCRIPT_NAME) RedisScript<List<Long>> redisScript,Validator validator) {return new CustomRedisRateLimiter(redisTemplate, redisScript, validator);}@Beanpublic RateLimiterGatewayFilterFactory rateLimiterGatewayFilterFactory(CustomRedisRateLimiter customRedisRateLimiter, CustomKeyResolver customKeyResolver) {return new RateLimiterGatewayFilterFactory(customRedisRateLimiter, customKeyResolver);} server.port: 8082spring:application:name: gatewayredis:host: localhostport: 6379password: 123456cloud:gateway:routes:- id: rateLimit_routeuri: http://localhost:8000order: 0predicates:- Path=/foo/**filters:- StripPrefix=1- name: RateLimiter熔斷
? ? ? 當(dāng)下游接口負載很大,或者接口不通等其他原因?qū)е鲁瑫r,如果接口不熔斷的話將會影響到下游接口得不到喘息,網(wǎng)關(guān)也會因為超時連接一直掛起,很可能因為一個子系統(tǒng)的問題導(dǎo)致整個系統(tǒng)的雪崩。所以我們的網(wǎng)關(guān)需要設(shè)計熔斷,當(dāng)因為熔斷器打開時,網(wǎng)關(guān)將返回一個降級的應(yīng)答。
熔斷配置如下:
server.port: 8082spring:application:name: gatewayredis:host: localhostport: 6379password: 123456cloud:gateway:routes:- id: rateLimit_routeuri: http://localhost:8000order: 0predicates:- Path=/foo/**filters:- StripPrefix=1- name: RateLimiter- name: Hystrixargs:name: fallbackcmdfallbackUri: forward:/fallback? hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds: 5000
package org.gateway.controller;import org.gateway.response.Response; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class FallbackController {@GetMapping("/fallback")public Response fallback() {Response response = new Response();response.setCode("100");response.setMessage("服務(wù)暫時不可用");return response;} }?
注意需要設(shè)置commandKey的超時時間。其他的hystrix配置請訪問Hystrix wiki.
動態(tài)配置路由和過濾器
最后我們來看一下如何動態(tài)配置路由和過濾器。
定義路由實體
/*** Gateway的路由定義模型*/ public class GatewayRouteDefinition {/*** 路由的Id*/private String id;/*** 路由斷言集合配置*/private List<GatewayPredicateDefinition> predicates = new ArrayList<>();/*** 路由過濾器集合配置*/private List<GatewayFilterDefinition> filters = new ArrayList<>();/*** 路由規(guī)則轉(zhuǎn)發(fā)的目標uri*/private String uri;/*** 路由執(zhí)行的順序*/private int order = 0; }?
路由斷言實體
/*** 路由斷言定義模型*/ public class GatewayPredicateDefinition {/*** 斷言對應(yīng)的Name*/private String name;/*** 配置的斷言規(guī)則*/private Map<String, String> args = new LinkedHashMap<>();}
?
過濾器實體
/*** 過濾器定義模型*/ public class GatewayFilterDefinition {/*** Filter Name*/private String name;/*** 對應(yīng)的路由規(guī)則*/private Map<String, String> args = new LinkedHashMap<>(); }?
路由增刪改controller
package org.gateway.controller;import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map;import org.gateway.model.GatewayFilterDefinition; import org.gateway.model.GatewayPredicateDefinition; import org.gateway.model.GatewayRouteDefinition; import org.gateway.route.DynamicRouteServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.UriComponentsBuilder;@RestController @RequestMapping("/route") public class RouteController {@Autowiredprivate DynamicRouteServiceImpl dynamicRouteService;/*** 增加路由* @param gwdefinition* @return*/@PostMapping("/add")public String add(@RequestBody GatewayRouteDefinition gwdefinition) {try {RouteDefinition definition = assembleRouteDefinition(gwdefinition);return this.dynamicRouteService.add(definition);} catch (Exception e) {e.printStackTrace();}return "succss";}@GetMapping("/delete/{id}")public String delete(@PathVariable String id) {return this.dynamicRouteService.delete(id);}@PostMapping("/update")public String update(@RequestBody GatewayRouteDefinition gwdefinition) {RouteDefinition definition = assembleRouteDefinition(gwdefinition);return this.dynamicRouteService.update(definition);}private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {RouteDefinition definition = new RouteDefinition();List<PredicateDefinition> pdList=new ArrayList<>();definition.setId(gwdefinition.getId());List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {PredicateDefinition predicate = new PredicateDefinition();predicate.setArgs(gpDefinition.getArgs());predicate.setName(gpDefinition.getName());pdList.add(predicate);}List<GatewayFilterDefinition> gatewayFilterDefinitions = gwdefinition.getFilters();List<FilterDefinition> filterList = new ArrayList<>();if (!CollectionUtils.isEmpty(gatewayFilterDefinitions)) {for (GatewayFilterDefinition gatewayFilterDefinition : gatewayFilterDefinitions) {FilterDefinition filterDefinition = new FilterDefinition();filterDefinition.setName(gatewayFilterDefinition.getName());filterDefinition.setArgs(gatewayFilterDefinition.getArgs());filterList.add(filterDefinition);}}definition.setPredicates(pdList);definition.setFilters(filterList);URI uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();definition.setUri(uri);return definition;} }?動態(tài)路由service?
package org.gateway.route;import java.net.URI; import java.util.Arrays; import java.util.HashMap; import java.util.Map;import org.gateway.model.GatewayPredicateDefinition; import org.gateway.model.GatewayRouteDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.stereotype.Service; import org.springframework.web.util.UriComponentsBuilder;import com.alibaba.fastjson.JSON;import reactor.core.publisher.Mono;@Service public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;private ApplicationEventPublisher publisher;/*** 增加路由* @param definition* @return*/public String add(RouteDefinition definition) {routeDefinitionWriter.save(Mono.just(definition)).subscribe();this.publisher.publishEvent(new RefreshRoutesEvent(this));return "success";}/*** 更新路由* @param definition* @return*/public String update(RouteDefinition definition) {try {this.routeDefinitionWriter.delete(Mono.just(definition.getId()));} catch (Exception e) {return "update fail,not find route routeId: "+definition.getId();}try {routeDefinitionWriter.save(Mono.just(definition)).subscribe();this.publisher.publishEvent(new RefreshRoutesEvent(this));return "success";} catch (Exception e) {return "update route fail";}}/*** 刪除路由* @param id* @return*/public String delete(String id) {try {this.routeDefinitionWriter.delete(Mono.just(id));return "delete success";} catch (Exception e) {e.printStackTrace();return "delete fail";}}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.publisher = applicationEventPublisher;} }?
?上面 routeDefinitionWriter的實現(xiàn)默認是InMemoryRouteDefinitionRepository,將路由存在內(nèi)存中,我們可以自己實現(xiàn)一個將路由存在redis中的repository。 this.publisher.publishEvent(new RefreshRoutesEvent(this));則會將CachingRouteLocator中的路由緩存清空。以上只是springcloud gateway支持的一小部分功能。
雖然springcloud gateway 才發(fā)布不久,相關(guān)的文檔還不是很完善,代碼中充滿了TODO的地方,react代碼友好性低。但是由于它的高性能而且是spring自己的框架,未來取代zuul不是沒有可能。
轉(zhuǎn)載于:https://www.cnblogs.com/qianwei/p/10127700.html
總結(jié)
以上是生活随笔為你收集整理的使用springcloud gateway搭建网关(分流,限流,熔断)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打包java程序生成exe
- 下一篇: gentoo rt-thread sco