1 创建动态路由表
在nacos上新增一个配置,专门用来配置网关路由信息,格式为json格式,如下所示:
{
# 是否要更新路由表信息标识
"refreshGatewayRoute":true,
"routeList":[
{
# 唯一标识
"id":"project1",
"predicates":[
{
"name":"Path",
"args":{
"pattern":"/project/**"
}
}
],
"filters":[
{
"name":"StripPrefix",
"args":{
"parts":"1"
}
}
],
"uri":"lb://myproject",
"order":0
}
]
}
2 配置动态路由表信息
在网关的配置文件中添加路由表在nacos上的配置信息,包括server-addr、namespace、group和data-id,如下所示:
#动态路由相关配置
dynamic:
route:
data-id: dynamic-route
group: ROUTE_GROUP
server-addr: 127.0.0.1:8848
namespace: b852f9b9-1d45-4dc7-a1c5-2c9169856836
3 创建实体类
- 过滤器类
import java.util.LinkedHashMap;
import java.util.Map;
/**
* FilterEntity
* @Description: 过滤器实体
* @author: Steven_sf
* @Date: 2020年02月14日
*/
public class FilterEntity {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getArgs() {
return args;
}
public void setArgs(Map<String, String> args) {
this.args = args;
}
}
- 断言实体类
import java.util.LinkedHashMap;
import java.util.Map;
/**
* PredicateEntity
* @Description: 断言
* @author: Steven_sf
* @Date: 2020年02月14日
*/
public class PredicateEntity {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, String> getArgs() {
return args;
}
public void setArgs(Map<String, String> args) {
this.args = args;
}
}
- 路由实体类
import java.util.ArrayList;
import java.util.List;
/**
* RouteEntity
* @Description: 路由实体
* @author: Steven_sf
* @Date: 2020年02月14日
*/
public class RouteEntity {
//路由id
private String id;
//路由断言集合
private List<PredicateEntity> predicates = new ArrayList<>();
//路由过滤器集合
private List<FilterEntity> filters = new ArrayList<>();
//路由转发的目标uri
private String uri;
//路由执行的顺序
private int order = 0;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<PredicateEntity> getPredicates() {
return predicates;
}
public void setPredicates(List<PredicateEntity> predicates) {
this.predicates = predicates;
}
public List<FilterEntity> getFilters() {
return filters;
}
public void setFilters(List<FilterEntity> filters) {
this.filters = filters;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
4 添加监听器
添加监听器,监听动态路由表配置变化情况。
/**
* DynamicRoutingConfig
* @Description: 监听器
* @author: Steven_sf
* @Date: 2020年02月14日
*/
@Component
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {
@Value("${dynamic.route.server-addr}")
private String serverAddr;
@Value("${dynamic.route.namespace}")
private String namespace;
@Value("${dynamic.route.data-id}")
private String dataId;
@Value("${dynamic.route.group}")
private String group;
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher applicationEventPublisher;
@Bean
public void refreshRouting() throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
ConfigService configService = NacosFactory.createConfigService(properties);
// 网关启动时,获取初始化路由信息,进行初始化操作
initRoute(configService);
// 监听路由信息变化情况
configService.addListener(dataId, group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
// 获取动态刷新路由信息对标识:true-刷新路由信息;false-不刷新路由信息
boolean refreshGatewayRoute = JSONObject.parseObject(configInfo).getBoolean("refreshGatewayRoute");
if (refreshGatewayRoute) {
List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(configInfo).getString("routeList")).toJavaList(RouteEntity.class);
// 更新路由表
for (RouteEntity route : list) {
updateRoute(assembleRouteDefinition(route));
}
}
}
});
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* 初始化路由信息
* @param configService
* @throws NacosException
*/
private void initRoute(ConfigService configService) throws NacosException{
String initRouteInfo = configService.getConfig(dataId, group, 60000);
List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(initRouteInfo).getString("routeList")).toJavaList(RouteEntity.class);
for (RouteEntity route : list) {
saveRoute(assembleRouteDefinition(route));
}
}
/**
* 路由更新:先删除旧的路由信息,再保存新的路由信息
* @param routeDefinition
* @return
*/
public void updateRoute(RouteDefinition routeDefinition){
deleteRoute(routeDefinition);
saveRoute(routeDefinition);
}
/**
* 保存路由信息
* @param routeDefinition
* @return
*/
public void saveRoute(RouteDefinition routeDefinition){
try {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
}catch (Exception e){
log.error(e.getMessage(), e);
}
}
/**
* 删除路由信息
* @param routeDefinition
* @return
*/
public void deleteRoute(RouteDefinition routeDefinition){
try {
this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
}catch (Exception e){
log.error(e.getMessage(), e);
}
}
/**
* 实体信息解析
* @param routeDefinition
* @return
*/
public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
RouteDefinition definition = new RouteDefinition();
definition.setId(routeEntity.getId());
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);
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);
URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
definition.setUri(uri);
return definition;
}
}