物联网架构成长之路(54)-基于Nacos+Gateway实现动态路由

0. 前言
  本来就负责一些小事情,但是还是要搞事情。把一个小项目切分成微服务,练练手。
  主要是以Nacos为配置中心,实现Spring Cloud GateWay的动态路由功能。然后在实现日志、鉴权等功能。动态路由,就是在Spring Cloud Gateway启动的时候,将路由配置和规则加载到内存里,但是通过集成Nacos,增加一个监听器,就可以在不重启网关,实现对应路由的配置和规则更新。实现动态路由。


1. 集成Nacos和Spring Cloud GateWay
  pom.xml

 1         <dependency>
 2             <groupId>org.springframework.boot</groupId>
 3             <artifactId>spring-boot-starter-actuator</artifactId>
 4         </dependency>
 5         
 6         <!-- Gateway Nacos Sentinel 网关路由、配置中心、服务器注册中心、流量控制、熔断降级 -->
 7         <dependency>
 8             <groupId>org.springframework.cloud</groupId>
 9             <artifactId>spring-cloud-starter-gateway</artifactId>
10         </dependency>
11         <dependency>
12             <groupId>com.alibaba.cloud</groupId>
13             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
14         </dependency>
15         <dependency>
16             <groupId>com.alibaba.cloud</groupId>
17             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
18         </dependency>
19         <dependency>
20             <groupId>com.alibaba.cloud</groupId>
21             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
22         </dependency>

  bootstrap.properties

1 #dev/test/prod
2 spring.profiles.active=dev
3 #nacos
4 spring.cloud.nacos.server-addr=127.0.0.1:8848
5 spring.cloud.nacos.config.namespace=0e152861-1efa-62ea-9125-e569abc29691
6 spring.cloud.nacos.discovery.namespace=0e152861-1efa-62ea-9125-e569abc29691
7 spring.cloud.nacos.config.prefix=xxxx-story-gateway
8 spring.cloud.nacos.config.file-extension=properties

 

2. 配置动态路由到Nacos

  具体配置路由信息

 1 [{
 2     "id": "xxxx-story-res",
 3     "order": 1,
 4     "predicates": [{
 5         "args": {
 6             "pattern": "/res/v1/**"
 7         },
 8         "name": "Path"
 9     }],
10     "uri": "lb://xxxx-story-res"
11 },{
12     "id": "xxxx-story-aiml",
13     "order": 2,
14     "predicates": [{
15         "args": {
16             "pattern": "/aiml/v1/**"
17         },
18         "name": "Path"
19     }],
20     "uri": "lb://xxxx-story-aiml"
21 }]

 

3. Java代码里增加一个BeanConfig就可以实现
  DynamicRouteConfig.java

  1 package com.wunaozai.demo.story.gateway.config;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 import java.util.Properties;
  6 import java.util.concurrent.Executor;
  7 
  8 import javax.annotation.PostConstruct;
  9 
 10 import org.slf4j.Logger;
 11 import org.slf4j.LoggerFactory;
 12 import org.springframework.beans.factory.annotation.Autowired;
 13 import org.springframework.beans.factory.annotation.Value;
 14 import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
 15 import org.springframework.cloud.gateway.route.RouteDefinition;
 16 import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
 17 import org.springframework.context.ApplicationEventPublisher;
 18 import org.springframework.context.ApplicationEventPublisherAware;
 19 import org.springframework.stereotype.Service;
 20 
 21 import com.alibaba.fastjson.JSONObject;
 22 import com.alibaba.nacos.api.NacosFactory;
 23 import com.alibaba.nacos.api.config.ConfigService;
 24 import com.alibaba.nacos.api.config.listener.Listener;
 25 
 26 import reactor.core.publisher.Mono;
 27 
 28 /**
 29  * 动态路由,可以通过获取Bean才做该类,提供增删改查已经发布功能
 30  * @author wunaozai
 31  * @Date 2020-03-16
 32  */
 33 @Service
 34 public class DynamicRouteConfig implements ApplicationEventPublisherAware {
 35 
 36     private static final Logger log = LoggerFactory.getLogger(DynamicRouteConfig.class);
 37 
 38     @Autowired
 39     private RouteDefinitionWriter routedefinitionWriter;
 40     
 41     private ApplicationEventPublisher publisher;
 42     
 43     private String dataId = "gateway-router.properties";
 44     private String group = "DEFAULT_GROUP";
 45     @Value("${spring.cloud.nacos.server-addr}")
 46     private String serverAddr;
 47     @Value("${spring.cloud.nacos.config.namespace}")
 48     private String namespace;
 49     
 50     private static final List<String> ROUTE_LIST = new ArrayList<>();
 51     
 52     @PostConstruct
 53     public void dynamicRouteByNacosListener() {
 54         try {
 55             Properties prop = new Properties();
 56             prop.put("serverAddr", serverAddr);
 57             prop.put("namespace", namespace);
 58             ConfigService config = NacosFactory.createConfigService(prop);
 59             String content = config.getConfig(dataId, group, 5000);
 60             publisher(content);
 61             config.addListener(dataId, group, new Listener() {
 62                 @Override
 63                 public void receiveConfigInfo(String config) {
 64                     publisher(config);
 65                 }
 66                 @Override
 67                 public Executor getExecutor() {
 68                     return null;
 69                 }
 70             });
 71         } catch (Exception e) {
 72             e.printStackTrace();
 73         }
 74     }
 75     
 76     /**
 77      * 增加路由
 78      * @param def
 79      * @return
 80      */
 81     public Boolean addRoute(RouteDefinition def) {
 82         try {
 83             routedefinitionWriter.save(Mono.just(def)).subscribe();
 84             ROUTE_LIST.add(def.getId());    
 85         } catch (Exception e) {
 86             e.printStackTrace();
 87         }
 88         return true;
 89     }
 90     /**
 91      * 删除路由
 92      * @return
 93      */
 94     public Boolean clearRoute() {
 95         for(String id: ROUTE_LIST) {
 96             routedefinitionWriter.delete(Mono.just(id)).subscribe();
 97         }
 98         ROUTE_LIST.clear();
 99         return false;
100     }
101     /**
102      * 发布路由
103      */
104     private void publisher(String config) {
105         clearRoute();
106         try {
107             log.info("重新更新动态路由");
108             List<RouteDefinition> gateway = JSONObject.parseArray(config, RouteDefinition.class);
109             for(RouteDefinition route: gateway) {
110                 addRoute(route);
111             }
112             publisher.publishEvent(new RefreshRoutesEvent(this.routedefinitionWriter));
113         } catch (Exception e) {
114             e.printStackTrace();
115         }
116         
117     }
118     
119     @Override
120     public void setApplicationEventPublisher(ApplicationEventPublisher app) {
121         publisher = app;
122     }
123 
124 }

  请求不同的URL转发到不同的服务器上
  /res/v1/**
  /aiml/v1/**


  至此就完成简单的动态路由功能了。我们修改nacos上的 gateway-router.properties ,程序会自动执行 DynamicRouteConfig.java 里面的 receiveConfigInfo 方法。动态加载配置,动态发布更新路由。
  用到Gateway,一般是用来实现鉴权,限流,熔断,网关路由,日志等功能。这一篇介绍了网关路由功能,由于SpringBoot默认就有日志功能,这里就不展开说。下一篇将介绍集成Sentinel的限流和熔断。再下一篇是介绍基于SpringBoot Secret 的Oauth2.0鉴权,结合到该项目中。

 


参考资料:
  https://blog.csdn.net/zhangchangbin123/article/details/89310353

本文地址:https://www.cnblogs.com/wunaozai/p/12512753.html
本系列目录: https://www.cnblogs.com/wunaozai/p/8067577.html
个人主页:https://www.wunaozai.com/

posted @ 2020-03-19 18:32  无脑仔的小明  阅读(3822)  评论(6编辑  收藏  举报