Talk is cheap,show you the code!
1.pom.xml中需要引入的主要依赖
<!-- Spring cloud gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
<!-- nacos服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--json解析-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2.配置属性
/**
* 自定义属性绑定值,可通过配置文件配置属性。
*/
@ConfigurationProperties(prefix = "timing.nacos.gateway")
@Configuration
public class NacosGatewayProperties {
private String address;
private String dataId;
private String groupId;
private Long timeout;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public Long getTimeout() {
return timeout;
}
public void setTimeout(Long timeout) {
this.timeout = timeout;
}
}
注:此处设置了配置项的prefix为timing.nacos.gateway ,后文的配置要保持一致。
3.配置文件
主要配置信息如下,注意timing.nacos.gateway:
#nacos配置中心、注册掌心
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
enabled: true
gateway:
discovery:
locator:
enabled: true
# 从nacos配置中获取路由,支持动态刷新
timing:
nacos:
gateway:
address: 127.0.0.1:8848
dataId: gateway
groupId: GATE_GROUP
timeout: 5000
4.核心代码
4.1 继承ApplicationEventPublisherAware,提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
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.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
*/
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
private final RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
public DynamicRouteServiceImpl(RouteDefinitionWriter routeDefinitionWriter) {
this.routeDefinitionWriter = routeDefinitionWriter;
}
/**
* 增加路由
*
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(definition));
return "success";
}
/**
* 更新路由
*
* @param definition
* @return
*/
public String update(RouteDefinition definition) {
try {
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception e) {
return "update fail,not find route routeId: " + definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(definition));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
public String updateBatch(List<RouteDefinition> list) {
if (CollectionUtils.isEmpty(list))
return "success";
try {
list.forEach(definition -> {
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
});
} catch (Exception e) {
return "update fail,delete error";
}
try {
list.forEach(definition -> {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
});
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 删除路由
*
* @param id
* @return
*/
public String delete(String id) {
try {
this.routeDefinitionWriter.delete(Mono.just(id));
return "delete success";
} catch (Exception e) {
e.printStackTrace();
return "delete fail";
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
4.2 实现runner,监听nacos路由配置变化,下发动态路由配置
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fline.gateway.config.NacosGatewayProperties;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.Executor;
/**
* 实现runner,通过nacos下发动态路由配置
*/
@Component
public class DynamicRouteServiceImplByNacos implements CommandLineRunner {
private final DynamicRouteServiceImpl dynamicRouteService;
private final NacosGatewayProperties nacosGatewayProperties;
public DynamicRouteServiceImplByNacos(DynamicRouteServiceImpl dynamicRouteService, NacosGatewayProperties nacosGatewayProperties) {
this.dynamicRouteService = dynamicRouteService;
this.nacosGatewayProperties = nacosGatewayProperties;
}
/**
* 监听Nacos Server下发的动态路由配置
*/
public void dynamicRouteByNacosListener() {
try {
ConfigService configService = NacosFactory.createConfigService(nacosGatewayProperties.getAddress());
String content = configService.getConfig(nacosGatewayProperties.getDataId(), nacosGatewayProperties.getGroupId(), nacosGatewayProperties.getTimeout());
System.out.println(content);
List<RouteDefinition> list = JSON.parseArray(content, RouteDefinition.class);
if (!CollectionUtils.isEmpty(list))
dynamicRouteService.updateBatch(list);
configService.addListener(nacosGatewayProperties.getDataId(), nacosGatewayProperties.getGroupId(), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
List<RouteDefinition> list = JSON.parseArray(configInfo, RouteDefinition.class);
dynamicRouteService.updateBatch(list);
}
@Override
public Executor getExecutor() {
return null;
}
});
} catch (NacosException e) {
e.printStackTrace();
}
}
@Override
public void run(String... args) {
dynamicRouteByNacosListener();
}
}
5.配置nacos
在[配置管理]-[配置列表]页面添加一条记录并发布。
配置内容与第2步ymal中的配置保持相同。即Data ID:gateway,Group:GATE_GROUP,配置格式选择json,配置内容为spring cloud gateway的路由配置信息,根据自己的情况填写,如下为样例:
[
{
"id": "timing-portal",
"order": 0,
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/portal/**" }
}
],
"filters": [],
"uri": "lb://timing-portal"
},{
"id": "timing-order",
"order": 1,
"predicates": [{
"name": "Path",
"args": {
"pattern": "/order/**" }
}],
"filters": [],
"uri": "lb://timing-order"
}
]
注:以上配置了两个服务,timing-portal为系统服务,该名称与该服务的配置文件中的spring.application.name要保持相同,也即要与注册到注册中心的服务名称相同,路由规则为以portal开头的请求都路由到该服务,使用 lb:// 实现集群服务访问。timing-order同理。
欢迎来我的个人网站逛逛:往后码生