经过上一篇我们发现nacos通过配置动态路由routes-api-gateway.yaml配置json,监听动态路由变化即可实现动态路由,非常的银杏化。

那么有的小伙伴发现配置json也比较麻烦,有没有更简单更银杏的办法?

改造上一篇的内容:让其他微服务启动完成后自动配置路由信息,简单粗暴更银杏化

上一篇地址:https://blog.csdn.net/CarryBest/article/details/112985659

先看一下路由需要的几个参数

- id: service11

uri: lb://service1

predicates:

- Path=/api/service1/**

filters:

- StripPrefix=2

需要id(唯一性)、url转发的服务名(我们注册的服务名)、predicates断言匹配原则、filters转发服务时候的过滤器这4个参数。

然后我们再打开nacos配置中心,找到public命名空间下的服务(本项目所有服务都注册到public下的),f12看一下,http://xxx.xxx.xxx.xxx:8848/nacos/v1/ns/catalog/services?hasIpCount=true&withInstances=false&pageNo=1&pageSize=10接口返回了我们所有注册的服务。如果你是在dev或者其他命名空间 只需要在url后添加&namespaceId=相应命名空间即可。

{"serviceList": [{"name": "service1","groupName": "DEFAULT_GROUP","clusterCount": 1,"ipCount": 1,"healthyInstanceCount": 1,"triggerFlag": "false"},{"name": "service2","groupName": "DEFAULT_GROUP","clusterCount": 1,"ipCount": 1,"healthyInstanceCount": 1,"triggerFlag": "false"}],"count": 34
}

经过上面点的分析,可以发现,可以通过接口获取所有的注册服务, 那么能不能在服务启动注册到naocs后,路由自己更新呢?其实是可以的。路由需要4个参数

1:id

可以使用serviceList返回的服务名

2:uri

可以使用serviceList返回的服务名,前缀拼上lb://

3:predicates

可以默认- Path=/服务名/**

4:filters

由于上面的断言predicates只有一级,那么这里默认- StripPrefix=1

步骤

1:需要配置到网关的项目(这里的服务不是网关,是指需要进过网关的服务)启动成功后调用自定义方法触发动态路由刷新

2:调用naocs的api获取所有服务

3:解析nacos返回的服务集合,拼接好后当做参数给动态路由

一:新建工程common-dynamic-route

提取动态配置相关类,工程截图如下

二:新建动态路由类

package com.carry.www.dynamic.route.config;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.carry.www.dynamic.route.entity.FilterEntity;
import com.carry.www.dynamic.route.entity.PredicateEntity;
import com.carry.www.dynamic.route.entity.RouteEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.list.PredicatedList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
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.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.*;
import java.util.concurrent.Executor;/*** 从Nacos获取动态路由* 实现ApplicationEventPublisherAware发布接口来发布路由更新事件*/
@Configuration
@Component
@Slf4j
public class DynamicRoutingConfigForApp implements ApplicationEventPublisherAware {@Value("${dynamic.route.server-addr}")private String serverAddr;@Value("${nacos.namespace}")private String namespace;@Value("${dynamic.route.data-id}")private String dataId;@Value("${dynamic.route.group}")private String groupId;// 保存、删除路由服务@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;private ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}/*** @return* @Author carryer* @Description 获取nacos配置服务* @Date* @Param**/public ConfigService getNacosConfigInfo() throws Exception {Properties properties = new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverAddr);properties.setProperty(PropertyKeyConst.NAMESPACE, namespace);ConfigService configService = NacosFactory.createConfigService(properties);return configService;}/*** @return* @Author carryer* @Description 刷新路由* @Date* @Param**/public void refreshRouting() throws IOException {String resultContent = "";//http://xxx.xxx.xxx.xxx:8848/nacos/v1/ns/catalog/services?hasIpCount=true&withInstances=false&pageNo=1&pageSize=10String url = "http://" + this.serverAddr + "/nacos/v1/ns/catalog/services?hasIpCount=true&withInstances=false&pageNo=1&pageSize=1000";List<String> params = new LinkedList<>();SelfHttp.HttpResult result = SelfHttp.doGet(url, "UTF-8", params);if (result.code == HttpURLConnection.HTTP_OK) {resultContent = result.content;}System.out.println(resultContent);if (StringUtils.isNotBlank(resultContent)) {JSONObject jsonObject = (JSONObject) JSONObject.parse(resultContent);List<Map> listMap = (List<Map>) jsonObject.get("serviceList");List<RouteEntity> list = new ArrayList<>();for (Map m : listMap) {String appName = String.valueOf(m.get("name"));RouteEntity routeEntity = new RouteEntity();routeEntity.setId(appName);routeEntity.setUri("lb://" + appName);List<FilterEntity> filters = new ArrayList<>();FilterEntity filterEntity = new FilterEntity();Map<String, String> args = new HashMap<>();args.put("parts", "1");filterEntity.setName("StripPrefix");filterEntity.setArgs(args);routeEntity.setFilters(filters);PredicateEntity predicateEntity = new PredicateEntity();predicateEntity.setName("Path");args.clear();args = new HashMap<>();args.put("pattern", "/" + appName + "/**");predicateEntity.setArgs(args);List<PredicateEntity> predicates = new ArrayList<>();predicates.add(predicateEntity);routeEntity.setPredicates(predicates);list.add(routeEntity);}//获取路由集合try {//更新路由表list.stream().forEach(x -> {try {update(assembleRouteDefinition(x));} catch (Exception e) {e.printStackTrace();}});} catch (Exception e) {}}}/*** @return* @Author carryer* @Description 路由更新* @Date* @Param**/private void update(RouteDefinition routeDefinition) throws Exception {//先删除路由routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));//再保存路由routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();//发布事件 发布者是RefreshRoutesEvent  事件是刷新路由applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));}/*** @return* @Author carryer* @Description 实体信息解析* @Date* @Param**/private RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {RouteDefinition definition = new RouteDefinition();// IDdefinition.setId(routeEntity.getId());// Predicates断言List<PredicateDefinition> pdList = new ArrayList<>();for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {PredicateDefinition predicateDefinition = new PredicateDefinition();predicateDefinition.setArgs(predicateEntity.getArgs());predicateDefinition.setName(predicateEntity.getName());pdList.add(predicateDefinition);}definition.setPredicates(pdList);// Filters过滤器List<FilterDefinition> fdList = new ArrayList<>();for (FilterEntity filterEntity : routeEntity.getFilters()) {FilterDefinition filterDefinition = new FilterDefinition();filterDefinition.setArgs(filterEntity.getArgs());filterDefinition.setName(filterEntity.getName());fdList.add(filterDefinition);}definition.setFilters(fdList);// URIURI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();definition.setUri(uri);return definition;}
}

三:改造HttpSimpleClient、ServerHttpAgent等源码

简单封装http类

package com.carry.www.dynamic.route.config; /*** @Title:* @Package* @Description:* @author carryer* @date 2021/1/2515:45*/import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.client.config.utils.MD5;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.alibaba.nacos.common.utils.VersionUtils;import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;/*** @Author carryer* @Description //TODO* @Date $ $* @Param $* @return $**/
public class SelfHttp {public static HttpResult doGet(String url, String encoding, List<String> paramValues) throws IOException {HttpURLConnection conn = null;try {conn = (HttpURLConnection) new URL(url).openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 100 ? ParamUtil.getConnectTimeout() : 100);conn.setReadTimeout(5000);List<String> newHeaders = getHeaders(url, new ArrayList<>(), paramValues);setHeaders(conn, newHeaders, encoding);conn.connect();int respCode = conn.getResponseCode();String resp = null;if (HttpURLConnection.HTTP_OK == respCode) {resp = IoUtils.toString(conn.getInputStream(), encoding);} else {resp = IoUtils.toString(conn.getErrorStream(), encoding);}return new HttpResult(respCode, conn.getHeaderFields(), resp);} finally {IoUtils.closeQuietly(conn);}}public static List<String> getHeaders(String url, List<String> headers, List<String> paramValues)throws IOException {List<String> newHeaders = new ArrayList<String>();newHeaders.add("exConfigInfo");newHeaders.add("true");newHeaders.add("RequestId");newHeaders.add(UuidUtils.generateUuid());if (headers != null) {newHeaders.addAll(headers);}return newHeaders;}static public void setHeaders(HttpURLConnection conn, List<String> headers, String encoding) {if (null != headers) {for (Iterator<String> iter = headers.iterator(); iter.hasNext(); ) {conn.addRequestProperty(iter.next(), iter.next());}}conn.addRequestProperty(HttpHeaderConsts.CLIENT_VERSION_HEADER, VersionUtils.VERSION);conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + encoding);String ts = String.valueOf(System.currentTimeMillis());String token = MD5.getInstance().getMD5String(ts + ParamUtil.getAppKey());conn.addRequestProperty(Constants.CLIENT_APPNAME_HEADER, ParamUtil.getAppName());conn.addRequestProperty(Constants.CLIENT_REQUEST_TS_HEADER, ts);conn.addRequestProperty(Constants.CLIENT_REQUEST_TOKEN_HEADER, token);}static public class HttpResult {final public int code;final public Map<String, List<String>> headers;final public String content;public HttpResult(int code, String content) {this.code = code;this.headers = null;this.content = content;}public HttpResult(int code, Map<String, List<String>> headers, String content) {this.code = code;this.headers = headers;this.content = content;}}
}

四:其他服务如何使用

1:其他服务把动态路由工程引入当前工程

<dependency><groupId>com.carry.www</groupId><artifactId>common-dynamic-route</artifactId><version>1.0.0</version>
</dependency>

2:然后在启动类启动成功后调用动态路由刷新

@Autowired
DynamicRoutingConfigForApp dynamicRoutingConfigForApp;
@Override
public void run(String... args) throws Exception {System.out.println("###################### 订单 服务启动完成!######################");System.out.println("###################### 自动注册路由 START!######################");dynamicRoutingConfigForApp.refreshRouting();System.out.println("###################### 自动注册路由 END!######################");
}

五:测试

为了方便直接使用网关测试,启动网关类,在网关启动成功的时候,也触发了动态路由的加载。

输入地址,使用网关地址+网关端口+配置到网关的服务名+方法名进行访问,http://localhost:9998/api-gatway/defaultfallback,api-gatway是我们注册的服务名也是路由的断言,成功进入断点,代表上面路由已经更新。

相关源码地址:https://github.com/tomducky/hdys-supporter

nacos动态路由配置(二)-微服务启动自动配置网关路由相关推荐

  1. 微服务框架搭建(网关路由)

    文章目录 前言 1.创建gateway工程 2.引入pom文件 3.注册进入nacos 4.添加路由规则 5.过滤器的使用 github地址 前言 当使用微服务的时候,需要区分哪些接口对外提供服务有些 ...

  2. 微服务架构中配置中心的选择

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:r6d.cn/XsTR 目前公司内部微服务架构基础设 ...

  3. 最新版Spring Cloud Alibaba微服务架构-Config配置中心篇

    文章目录 前言 一.Config引入背景 1.文件相对分散 2.无法区分环境 3.无法实时更新 4.安全无法保证 二.Config引入配置 1.配置文件格式 1.1 命名空间(Namespace) 1 ...

  4. 《深入理解 Spring Cloud 与微服务构建》第十章 路由网关 Spring Cloud Zuul

    <深入理解 Spring Cloud 与微服务构建>第十章 路由网关 Spring Cloud Zuul 文章目录 <深入理解 Spring Cloud 与微服务构建>第十章 ...

  5. 二. 微服务的高级进阶

    二. 微服务的高级进阶 1. Ribbon API和负载均衡算法 1. Ribbon API Ribbon 是一个独立的组件,是用来进行远程接口调用的,代码如下 @Slf4j @Service @Sc ...

  6. SpringCloud(第 025 篇)Zuul 路由后面的微服务挂了后,Zuul 提供了一种回退机制来应对熔断处理...

    2019独角兽企业重金招聘Python工程师标准>>> SpringCloud(第 025 篇)Zuul 路由后面的微服务挂了后,Zuul 提供了一种回退机制来应对熔断处理 一.大致 ...

  7. .Net Core微服务入门——Ocelot API网关接入(二)

    Net Core微服务入门--Ocelot API网关接入(二) 我们先接入Consul,实现服务发现 服务发现 1.引入 Ocelot.Provider.Consul 包 2.修改ocelot.js ...

  8. spring cloud+dotnet core搭建微服务架构:配置中心续(五)

    前言 上一章最后讲了,更新配置以后需要重启客户端才能生效,这在实际的场景中是不可取的.由于目前Steeltoe配置的重载只能由客户端发起,没有实现处理程序侦听服务器更改事件,所以还没办法实现彻底实现这 ...

  9. spring cloud+dotnet core搭建微服务架构:配置中心(四)

    前言 我们项目中有很多需要配置的地方,最常见的就是各种服务URL地址,这些地址针对不同的运行环境还不一样,不管和打包还是部署都麻烦,需要非常的小心.一般配置都是存储到配置文件里面,不管多小的配置变动, ...

最新文章

  1. 天平游码读数例题_电子天平偏载误差的检定与处理
  2. 简析TCP的三次握手与四次分手
  3. matlab中的@函数
  4. 学习Java的几大难题,你们都解决了吗?
  5. 中国多媒体大会(ChinaMM 2020) 征文通知
  6. MySQL数据库储存引擎Inoodb一--记录储存结构
  7. Solr 4.10.3 集成 IK Analyzer 2012FF 中文分词器
  8. 计算机网络速度慢原因,导致电脑网速变慢的七大原因
  9. CAML语法- Query写法
  10. 计算机英语性考任务答案,国开电大理工英语1单元自测7形考任务答案
  11. linux ftp强制删除,Linux FTP账号无法删除文件夹如何解决
  12. OpenCV 表盘指针自动读数
  13. 最全Android 11新特性概览
  14. Linux系统编程笔记(李慧琴) 2
  15. 买服务器不做网站需要备案吗,买服务器需要备案吗
  16. 《沈工智校》技术支持
  17. 模拟cmos集成电路(9)
  18. 【网络】远程连接路由器
  19. 游戏计算机性能要求吗,玩电脑大型游戏对于配置有什么要求
  20. kotlin实现bean的注入

热门文章

  1. 思科NGA设备中发现的高严重性漏洞,漏洞可导致未经身份验证即可远程攻击设备
  2. 【上海官方2019年】垃圾分类宣传资料
  3. 解决ARP攻击的方法(转)
  4. 从Twitter应用布局看国内微博应用发展趋势
  5. 资料链接 网络/系统/华为
  6. LW_OOPC学习02
  7. 飞书开放平台-查询已读消息示例
  8. MySQL安装的第三步出现红叉解决方法
  9. 帝国霸业银河生存开服教程——游戏
  10. 如何FTP远程访问UR机器人文件