物联网架构成长之路(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/
作者:无脑仔的小明 出处:http://www.cnblogs.com/wunaozai/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果文中有什么错误,欢迎指出。以免更多的人被误导。有需要沟通的,可以站内私信,文章留言,或者关注“无脑仔的小明”公众号私信我。一定尽力回答。 |