如何配置springcloud2.x版本Gateway动态路由
本篇内容主要讲解“如何配置spring cloud 2.x版本Gateway动态路由”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何配置spring cloud 2.x版本Gateway动态路由”吧!
我们提供的服务有:成都网站制作、成都网站建设、微信公众号开发、网站优化、网站认证、普宁ssl等。为成百上千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的普宁网站制作公司
spring cloud 2.x版本 Gateway动态路由教程
摘要
本文采用的Spring cloud为2.1.8RELEASE,version=Greenwich.SR3
前言
写了几篇关于Spring Cloud Gateway的文章后发现,Gateway涉及的知识范围太广了,真是深刻体会了“一入Spring cloud深似海”。
现实生产环境中,使用Spring Cloud Gateway都是作为所有流量的入口,为了保证系统的高可用,尽量避免系统的重启,所以需要Spring Cloud Gateway的动态路由来处理。之前的文章《Gateway路由网关教程》提供的路由配置,在系统启动时候,会将路由配置和规则加载到内存当中,无法做到不重启服务就可以动态的新增、修改、删除内存中的路由配置和规则。
简单的动态路由实现
Spring Cloud Gateway源码中提供了GatewayControllerEndpoint类来修改路由配置,但是官方文档好像并没有做详细的使用说明,只是简单介绍了几个简单的api接口。感兴趣的小伙伴可以先查看官方文档(第11章节 Actuator API)。
引致官方文档:
The
/gateway
actuator endpoint allows to monitor and interact with a Spring Cloud Gateway application. To be remotely accessible, the endpoint has to be enabled and exposed via HTTP or JMX in the application properties.
1.1 添加相关pom依赖
在原来spring-gateway的基础上增加spring-boot-starter-actuator依赖
org.springframework.boot spring-boot-starter-actuator
1.2 在application.yml中增加配置
management: endpoints: web: exposure: include: "*"
配置说明:management.endpoints.web.exposure.include 暴露所有的gateway端点
1.3 启动服务
启动服务,访问http://localhost:8100/actuator/gateway/routes,这是我们可以看到所有的routes信息。 image-20191102225203034.png 我们也可以访问单个路由信息:http://localhost:8100/actuator/gateway/routes/CompositeDiscoveryClient_EUREKA-CLIENT
显示如下:image-20191102225853005.png
1.4 增加、修改路由信息
Gateway默认使用的是GatewayControllerEndpoint这个类,GatewayControllerEndpoint又继承了AbstractGatewayControllerEndpoint类。
提供的方法:(只列具了几个相关方法,其他方法小伙们可以自行查看源码)
/gateway/routes 查询所有路由信息
/gateway/routes/{id} 根据路由id查询单个信息
/gateway/routes/{id} @PostMapping 新增一个路由信息
/gateway/routes/{id} @DeleteMapping 删除一个路由信息
1.4.1 新增路由
我们可根据/gateway/routes返回的路由信息,来模仿一个@PostMapping请求参数
{ "uri": "http://httpbin.org:80", "predicates": [ { "args": { "pattern": "/ribbon/**" }, "name": "Path" } ], "filters": [] }
这是我们可以通过postman来发送一个post请求,如图所示:
response返回1证明已经插入成功,我们可以通过http://localhost:8100/actuator/gateway/routes/查看路由信息,显示结果如下:
截图红框中的信息就是新增加的
1.4.2 删除路由信息
我们可以直接用postman模拟DeleteMapping请求,http://localhost:8100/actuator/gateway/routes/addroutes
显示如下:
这时候我们在访问http://localhost:8100/actuator/gateway/routes,可以看到新增加的路由已经被删除成功了。
1.5 小结
基于Spring Cloud Gateway默认方法实现的动态路由我就完成了,在前言中我已经提到了,这种方式是基于jvm内存实现,一旦服务重启,新增的路由配置信息就是完全消失了。所有这个时候我们可以考虑是否可以参考GatewayControllerEndpoint这类,自己实现一套动态路由方法,然后将路由信息持久化。
自定义动态路由
1.1定义相关类
1.1.1 定义实体类
可以自定义实体类,我这里偷了一个懒,直接用了Gateway的RouteDefinition类,感兴趣的小伙伴可以参考RouteDefinition类自己扩展,然后写一个Convert类将自定义的类转换成RouteDefinition就可以了。
1.1.2 自定义redisRouteDefinitionRepository类
我这边采用redis做为路由配置的信息的持久层,所以写了一个RedisRouteDefinitionRepository。
package spring.cloud.demo.spring.gateway.component; import com.google.common.collect.Lists; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionRepository; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.redis.RedisUtils; import spring.cloud.demo.spring.gateway.util.JsonUtils; import javax.annotation.Resource; import java.util.List; /** * @auther: maomao * @DateT: 2019-11-03 */ @Component public class RedisRouteDefinitionRepository implements RouteDefinitionRepository { //存储的的key private final static String KEY = "gateway_dynamic_route"; @Resource private RedisUtils redisUtils; /** * 获取路由信息 * @return */ @Override public FluxgetRouteDefinitions() { List gatewayRouteEntityList = Lists.newArrayList(); redisUtils.hgets(KEY).stream().forEach(route -> { RouteDefinition result = JsonUtils.parseJson(route.toString(), RouteDefinition.class); gatewayRouteEntityList.add(result); }); return Flux.fromIterable(gatewayRouteEntityList); } /** * 新增 * @param route * @return */ @Override public Mono save(Mono route) { return route.flatMap(routeDefinition -> { redisUtils.hset(KEY, routeDefinition.getId(), JsonUtils.toString(routeDefinition)); return Mono.empty(); }); } /** * 删除 * @param routeId * @return */ @Override public Mono delete(Mono routeId) { return routeId.flatMap(id -> { if (redisUtils.hHashKey(KEY, id)) { redisUtils.hdel(KEY, id); return Mono.empty(); } return Mono.defer(() -> Mono.error(new NotFoundException("route definition is not found, routeId:" + routeId))); }); } }
1.1.3 自定义Controller和Service
package spring.cloud.demo.spring.gateway.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; 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 reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.service.GatewayDynamicRouteService; import javax.annotation.Resource; /** * 自定义动态路由 * @auther: maomao * @DateT: 2019-11-03 */ @RestController @RequestMapping("/gateway") @Slf4j public class GatewayDynamicRouteController { @Resource private GatewayDynamicRouteService gatewayDynamicRouteService; @PostMapping("/add") public String create(@RequestBody RouteDefinition entity) { int result = gatewayDynamicRouteService.add(entity); return String.valueOf(result); } @PostMapping("/update") public String update(@RequestBody RouteDefinition entity) { int result = gatewayDynamicRouteService.update(entity); return String.valueOf(result); } @DeleteMapping("/delete/{id}") public Mono> delete(@PathVariable String id) { return gatewayDynamicRouteService.delete(id); } }
package spring.cloud.demo.spring.gateway.service; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; import spring.cloud.demo.spring.gateway.component.RedisRouteDefinitionRepository; import javax.annotation.Resource; /** * @auther: maomao * @DateT: 2019-11-03 */ @Service public class GatewayDynamicRouteService implements ApplicationEventPublisherAware { @Resource private RedisRouteDefinitionRepository redisRouteDefinitionRepository; private ApplicationEventPublisher applicationEventPublisher; /** * 增加路由 * @param routeDefinition * @return */ public int add(RouteDefinition routeDefinition) { redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe(); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); return 1; } /** * 更新 * @param routeDefinition * @return */ public int update(RouteDefinition routeDefinition) { redisRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId())); redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe(); applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this)); return 1; } /** * 删除 * @param id * @return */ public Mono> delete(String id) { return redisRouteDefinitionRepository.delete(Mono.just(id)).then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build()))) .onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build())); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } }
1.2 application.yml
application.yml配置要暴漏Gateway的所有端点,可以看考之前的配置信息。
1.3 启动服务
启动Spring cloud Gateway服务,先访问http://localhost:8100/actuator/gateway/routes,查看已有的路由配置信息。然后我们用postman请求add方法,http://localhost:8100/gateway/add,如果所示:
注意截图中红框的内容。证明已经新增成功。
这时我们在访问http://localhost:8100/actuator/gateway/routes查看结果。如果所示:
同理我们可以访问update和delete方法,我这里就不过多描述了。
总结
自定义动态路由核心原理其实就要重写网关模块,也就是之前提到的RedisRouteDefinitionRepository类。我这里偷懒没有重新定义对应的实体类,这里需要注意的是,传入参数一定要按照application.yml中配置的格式,然后转成json,如果格式不正确会报错。
代码地址
gitHub地址
spring cloud 2.x版本 Eureka Server服务注册中心教程
spring cloud 2.x版本 Eureka Client服务提供者教程
spring cloud 2.x版本 Ribbon服务发现教程(内含集成Hystrix熔断机制)
spring cloud 2.x版本 Feign服务发现教程(内含集成Hystrix熔断机制)
spring cloud 2.x版本 Zuul路由网关教程
spring cloud 2.x版本 config分布式配置中心教程
spring cloud 2.x版本 Hystrix Dashboard断路器教程
spring cloud 2.x版本 Gateway路由网关教程
spring cloud 2.x版本 Gateway自定义过滤器教程
spring cloud 2.x版本 Gateway熔断、限流教程
spring cloud 2.x版本 Gateway动态路由教程
到此,相信大家对“如何配置spring cloud 2.x版本Gateway动态路由”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
分享名称:如何配置springcloud2.x版本Gateway动态路由
URL分享:http://myzitong.com/article/poisgh.html