简介

该文档主要介绍以Nacos为配置中心,实现Spring Cloud GateWay 实现动态路由的功能。Spring Cloud Gateway启动时候,就将路由配置和规则加载到内存里,无法做到不重启网关就可以动态的对应路由的配置和规则进行增加,修改和删除。通过nacos的配置下发的功能可以实现在不重启网关的情况下,实现动态路由。

集成

Spring Cloud GateWay集成

spring-cloud-starter-gateway:路由转发、请求过滤(权限校验、限流以及监控等)

spring-boot-starter-webflux:反应式Web框架

spring-boot-starter-actuator:监控系统健康


   
   
  1. <dependency>

  2. <groupId>org.springframework.cloud</groupId>

  3. <artifactId>spring-cloud-starter-gateway</artifactId>

  4. </dependency>

  5. <dependency>

  6. <groupId>org.springframework.boot</groupId>

  7. <artifactId>spring-boot-starter-webflux</artifactId>

  8. </dependency>

  9. <dependency>

  10. <groupId>org.springframework.boot</groupId>

  11. <artifactId>spring-boot-starter-actuator</artifactId>

  12. </dependency>

Nacos集成

nacos-client:nacos客户端,现在用比较新的版本0.9.0


   
   
  1. <dependency>

  2. <groupId>com.alibaba.nacos</groupId>

  3. <artifactId>nacos-client</artifactId>

  4. <version>0.9.0</version>

  5. </dependency>

动态路由

DynamicRouteServiceImpl:提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。


   
   
  1. @Service

  2. public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

  3. @Autowired

  4. private RouteDefinitionWriter routeDefinitionWriter;

  5. private ApplicationEventPublisher publisher;

  6. /**

  7. * 增加路由

  8. * @param definition

  9. * @return

  10. */

  11. public String add(RouteDefinition definition) {

  12. routeDefinitionWriter.save(Mono.just(definition)).subscribe();

  13. this.publisher.publishEvent(new RefreshRoutesEvent(this));

  14. return "success";

  15. }

  16. /**

  17. * 更新路由

  18. * @param definition

  19. * @return

  20. */

  21. public String update(RouteDefinition definition) {

  22. try {

  23. this.routeDefinitionWriter.delete(Mono.just(definition.getId()));

  24. } catch (Exception e) {

  25. return "update fail,not find route routeId: "+definition.getId();

  26. }

  27. try {

  28. routeDefinitionWriter.save(Mono.just(definition)).subscribe();

  29. this.publisher.publishEvent(new RefreshRoutesEvent(this));

  30. return "success";

  31. } catch (Exception e) {

  32. return "update route fail";

  33. }

  34. }

  35. /**

  36. * 删除路由

  37. * @param id

  38. * @return

  39. */

  40. public String delete(String id) {

  41. try {

  42. this.routeDefinitionWriter.delete(Mono.just(id));

  43. return "delete success";

  44. } catch (Exception e) {

  45. e.printStackTrace();

  46. return "delete fail";

  47. }

  48. }

  49. @Override

  50. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

  51. this.publisher = applicationEventPublisher;

  52. }

  53. }

RouteDefinition: 提供路由实体类,主要有predicates匹配来自用户的请求,filters服务路由


   
   
  1. @Validated

  2. public class RouteDefinition {

  3. @NotEmpty

  4. private String id = UUID.randomUUID().toString();

  5. @NotEmpty

  6. @Valid

  7. private List<PredicateDefinition> predicates = new ArrayList<>();

  8. @Valid

  9. private List<FilterDefinition> filters = new ArrayList<>();

  10. @NotNull

  11. private URI uri;

  12. private int order = 0;

  13. public RouteDefinition() {}

  14. public RouteDefinition(String text) {

  15. int eqIdx = text.indexOf("=");

  16. if (eqIdx <= 0) {

  17. throw new ValidationException("Unable to parse RouteDefinition text '" + text + "'" +

  18. ", must be of the form name=value");

  19. }

  20. setId(text.substring(0, eqIdx));

  21. String[] args = tokenizeToStringArray(text.substring(eqIdx+1), ",");

  22. setUri(URI.create(args[0]));

  23. for (int i=1; i < args.length; i++) {

  24. this.predicates.add(new PredicateDefinition(args[i]));

  25. }

  26. }

  27. public String getId() {

  28. return id;

  29. }

  30. public void setId(String id) {

  31. this.id = id;

  32. }

  33. public List<PredicateDefinition> getPredicates() {

  34. return predicates;

  35. }

  36. public void setPredicates(List<PredicateDefinition> predicates) {

  37. this.predicates = predicates;

  38. }

  39. public List<FilterDefinition> getFilters() {

  40. return filters;

  41. }

  42. public void setFilters(List<FilterDefinition> filters) {

  43. this.filters = filters;

  44. }

  45. public URI getUri() {

  46. return uri;

  47. }

  48. public void setUri(URI uri) {

  49. this.uri = uri;

  50. }

  51. public int getOrder() {

  52. return order;

  53. }

  54. public void setOrder(int order) {

  55. this.order = order;

  56. }

  57. @Override

  58. public boolean equals(Object o) {

  59. if (this == o) return true;

  60. if (o == null || getClass() != o.getClass()) return false;

  61. RouteDefinition routeDefinition = (RouteDefinition) o;

  62. return Objects.equals(id, routeDefinition.id) &&

  63. Objects.equals(predicates, routeDefinition.predicates) &&

  64. Objects.equals(order, routeDefinition.order) &&

  65. Objects.equals(uri, routeDefinition.uri);

  66. }

  67. @Override

  68. public int hashCode() {

  69. return Objects.hash(id, predicates, uri);

  70. }

  71. @Override

  72. public String toString() {

  73. return "RouteDefinition{" +

  74. "id='" + id + '\'' +

  75. ", predicates=" + predicates +

  76. ", filters=" + filters +

  77. ", uri=" + uri +

  78. ", order=" + order +

  79. '}';

  80. }

  81. }

NacosGatewayProperties:自定义属性绑定值,可通过配置文件配置属性。


   
   
  1. @ConfigurationProperties(prefix="nacos", ignoreUnknownFields = true)

  2. @Configuration

  3. public class NacosGatewayProperties {

  4. private String address;

  5. private String dataId;

  6. private String groupId;

  7. private Long timeout;

  8. public String getAddress() {

  9. return address;

  10. }

  11. public void setAddress(String address) {

  12. this.address = address;

  13. }

  14. public String getDataId() {

  15. return dataId;

  16. }

  17. public void setDataId(String dataId) {

  18. this.dataId = dataId;

  19. }

  20. public String getGroupId() {

  21. return groupId;

  22. }

  23. public void setGroupId(String groupId) {

  24. this.groupId = groupId;

  25. }

  26. public Long getTimeout() {

  27. return timeout;

  28. }

  29. public void setTimeout(Long timeout) {

  30. this.timeout = timeout;

  31. }

  32. }

DynamicRouteServiceImplByNacos: 实现runner,通过nacos下发动态路由配置


   
   
  1. @Component

  2. public class DynamicRouteServiceImplByNacos implements CommandLineRunner{

  3. @Autowired

  4. private DynamicRouteServiceImpl dynamicRouteService;

  5. @Autowired

  6. private NacosGatewayProperties nacosGatewayProperties;

  7. /**

  8. * 监听Nacos Server下发的动态路由配置

  9. * @param dataId

  10. * @param group

  11. */

  12. public void dynamicRouteByNacosListener (){

  13. try {

  14. ConfigService configService=NacosFactory.createConfigService(nacosGatewayProperties.getAddress());

  15. String content = configService.getConfig(nacosGatewayProperties.getDataId(), nacosGatewayProperties.getGroupId(), nacosGatewayProperties.getTimeout());

  16. System.out.println(content);

  17. configService.addListener(nacosGatewayProperties.getDataId(), nacosGatewayProperties.getGroupId(), new Listener() {

  18. @Override

  19. public void receiveConfigInfo(String configInfo) {

  20. List<RouteDefinition> list = JsonUtils.toList(configInfo, RouteDefinition.class);

  21. list.forEach(definition->{

  22. dynamicRouteService.update(definition);

  23. });

  24. }

  25. @Override

  26. public Executor getExecutor() {

  27. return null;

  28. }

  29. });

  30. } catch (NacosException e) {

  31. e.printStackTrace();

  32. }

  33. }

  34. @Override

  35. public void run(String... args) throws Exception {

  36. dynamicRouteByNacosListener();

  37. }

  38. }

nacos配置下发

nacos配置


   
   
  1. nacos:

  2. address: 127.0.0.1:8848

  3. data-id: dhap-gateway

  4. group-id: AAA

  5. timeout: 5000

nacos属性文件定义

新建dataID为

groupID为AAA 


   
   
  1. [

  2. {

  3. "filters": [],

  4. "id": "blog1",

  5. "order": 0,

  6. "predicates": [{

  7. "args": {

  8. "pattern": "/z"

  9. },

  10. "name": "Path"

  11. }],

  12. "uri": "https://blog.csdn.net/zhangchangbin123"

  13. },

  14. {

  15. "filters": [],

  16. "id": "blog1",

  17. "order": 0,

  18. "predicates": [{

  19. "args": {

  20. "pattern": "/c"

  21. },

  22. "name": "Path"

  23. }],

  24. "uri": "https://blog.csdn.net/zhangchangbin123"

  25. }

  26. ]

查看路由信息

路由结果

-------------------------------------------------------------------

我的公众号

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐