java动态网关_Spring Cloud Gateway + Nacos 实现动态路由

本节开始介绍 SpringCloud Gateway 中动态路由的实现方法,包括:

Nacos 集成动态路由配置,更新配置文件即自动更新路由

MySQL + 二级缓存实现,主要基于 Gateway 的一些特性进行重写,实现路由信息的自动更新

这篇文章主要介绍第一种方式:将配置文件放到 Nacos 进行托管,网关服务通过引入 Nacos 而自动更新路由配置信息。实现较为简单。

下面进入正题。

1. 创建网关服务

创建一个 springboot gateway 网关服务,默认是从 yaml 文件中读取 route 的配置。如果想要从 nacos 中读取配置,就要引入 nacos-config的依赖,并设置配置文件的地址。

首先创建一个空 maven 项目 spring-cloud-gateway-nacos-routes,声明 springboot 和 springcloud 的版本,并引入 nacos。

org.springframework.boot

spring-boot-starter-parent

2.3.1.RELEASE

com.eknown

spring-cloud-gateway-nacos-routes

SpringCloud Gateway Nacos 动态路由示例

1.0-SNAPSHOT

1.8

Hoxton.SR6

org.springframework.boot

spring-boot-starter

org.springframework.cloud

spring-cloud-starter-alibaba-nacos-discovery

0.9.0.RELEASE

org.springframework.cloud

spring-cloud-dependencies

${spring-cloud.version}

pom

import

然后创建一个 springboot 项目,命名为:gateway-demo,引入 gateway/nacos-config 等依赖:

com.eknown

spring-cloud-gateway-nacos-routes

1.0-SNAPSHOT

gateway-demo

0.0.1-SNAPSHOT

gateway-demo

Demo project for Spring Boot

org.springframework.cloud

spring-cloud-starter-gateway

cn.hutool

hutool-core

5.3.9

org.springframework.cloud

spring-cloud-alibaba-nacos-config

0.9.0.RELEASE

org.springframework.boot

spring-boot-starter-data-redis-reactive

我们知道 SpringBoot 加载配置文件的顺序是:bootstrap.yml -> application.yml 这里需要将 nacos-config 的配置项放到 bootstrap.yml 中,这样项目启动时才能优先从 nacos 中加载配置信息。主要配置如下:

server:

port: 8501

spring:

application:

name: gateway-demo

cloud:

nacos:

discovery:

server-addr: 127.0.0.1:8848

config:

group: ${gateway.dynamicRoute.group}

file-extension: json

server-addr: 127.0.0.1:8848

gateway:

discovery:

locator:

enabled: true

redis:

host: localhost

password:

port: 6379

database: 10

# 自定义的配置项,用于设置路由信息所载的配置文件,比如这里是 group + dataId

gateway:

dynamicRoute:

enabled:  true

dataType: nacos

dataId: 'yq_routes'

group: 'YQ_GATEWAY'

将自定义配置项加载到 Java 中:

@Configuration

public class GatewayConfig {

public static String NACOS_DATA_ID;

public static String NACOS_GROUP_ID;

@Value("${gateway.dynamicRoute.dataId}")

public void setNacosDataId(String dataId) {

NACOS_DATA_ID = dataId;

}

@Value("${gateway.dynamicRoute.group}")

public void setNacosGroupId(String group) {

NACOS_GROUP_ID = group;

}

}

下面我们重写一下 RouteDefinitionRepository 接口,将其改造成使用 Nacos 引入路由配置信息就可以了!

public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

private static final Logger log = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);

// 更新路由信息需要的

private ApplicationEventPublisher publisher;

// nacos 的配置信息

private NacosConfigProperties nacosConfigProperties;

// 构造器

public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) {

this.publisher = publisher;

this.nacosConfigProperties = nacosConfigProperties;

System.out.println(GatewayConfig.NACOS_DATA_ID + ", " + GatewayConfig.NACOS_GROUP_ID);

addListener();

}

@Override

public Flux getRouteDefinitions() {

try {

String content = nacosConfigProperties.configServiceInstance()

.getConfig(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID,5000);

List routeDefinitions = getListByStr(content);

return Flux.fromIterable(routeDefinitions);

} catch (NacosException e) {

log.error("getRouteDefinitions by nacos error", e);

}

return Flux.fromIterable(CollUtil.newArrayList());

}

/**

* 添加Nacos监听

*/

private void addListener() {

try {

nacosConfigProperties.configServiceInstance().addListener(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID, new Listener() {

@Override

public Executor getExecutor() {

return null;

}

@Override

public void receiveConfigInfo(String configInfo) {

log.info("自动更新配置...\r\n" + configInfo);

publisher.publishEvent(new RefreshRoutesEvent(this));

}

});

} catch (NacosException e) {

log.error("nacos-addListener-error", e);

}

}

@Override

public Mono save(Mono route) {

return null;

}

@Override

public Mono delete(Mono routeId) {

return null;

}

// 从 json 中解析出路由配置信息 —— 所以配置文件的格式一定要写对!

private List getListByStr(String content) {

if (StrUtil.isNotEmpty(content)) {

return JSONObject.parseArray(content, RouteDefinition.class);

}

return new ArrayList<>(0);

}

}

最简单的方法是直接将这个 NacosRouteDefinitionRepository 类声明为 Bean。这里为了方便配置的切换写的复杂一点,通过 DynamicRouteConfig 来确认是否需要引入 nacos 的配置:

/**

* 动态路由配置

*/

@Configuration

@ConditionalOnProperty(prefix = "gateway.dynamicRoute", name = "enabled", havingValue = "true")

public class DynamicRouteConfig {

@Autowired

private ApplicationEventPublisher publisher;

/**

* Nacos实现方式

*/

@Configuration

@ConditionalOnProperty(prefix = "gateway.dynamicRoute", name = "dataType", havingValue = "nacos", matchIfMissing = true)

public class NacosDynRoute {

@Autowired

private NacosConfigProperties nacosConfigProperties;

@Bean

public NacosRouteDefinitionRepository nacosRouteDefinitionRepository() {

return new NacosRouteDefinitionRepository(publisher, nacosConfigProperties);

}

}

}

到这一步我们其实已经基本完成了 gateway + nacos 动态网关的实现了。下面我们测试一下。

2. 测试

创建一个简单的 springboot web 项目,引入 nacos 作为注册中心,并实现一个接口,比如:

server:

port: 8502

spring:

application:

name: demo

cloud:

nacos:

discovery:

server-addr: 127.0.0.1:8848

注:这里实际上不需要引入 nacos 作为注册中心的,因为路由实际上就是一个转发功能,这个转发操作是由 gateway 提供的,而不是 nacos 提供的。。。

接口:

@RestController

@RequestMapping(value = "test")

public class TestAction {

@GetMapping(value = "hello")

public String hello(String name) {

System.out.println("hello, " + name);

return "hello, " + name;

}

}

启动 nacos,添加配置文件,需要设置配置文件的 group 和 dataId 与上面的 gateway.dynamicRoute中的配置相同。

内容示例:

[

{

"id": "demo",

"uri": "lb://demo",

"predicates": [

{

"name": "Path",

"args": {

"pattern": "/api/demo/**"

}

}

],

"filters": [

{

"name": "StripPrefix",

"args": {

"parts": "2"

}

}

]

}

]

启动 gateway-demo 以及 demo 项目,访问 gateway-demo 项目对应的路由地址,比如这里的:http://localhost:8501/api/demo/test/hello,如果运行正常,请求将被转发到 demo 项目的/test/hello 接口,并返回对应的数据。

今天的分享就到这里啦!本来打算写一篇前文所说的第二种实现方法的文章的,不过由于二级缓存那边是用了组里封装的框架所以不便公布,后面有空我会自己实现一个基本的 demo,并同步到 Git 上!

水平有限,如有纰漏还请见谅。如果对文章内容有什么疑问,可以留言或直接联系我!thanks for your reading !

以上就是Spring Cloud Gateway + Nacos 实现动态路由的详细内容,更多关于SpringCloud Gateway 动态路由实现的资料请关注脚本之家其它相关文章!


版权声明:本文为weixin_35578119原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。