Nacos实现Zuul网关动态路由配置刷新

注意:如果Zuul网关应用注册到Eureka或Nacos,则会自动刷新路由配置,无需手动刷新

Nacos配置

1
2
3
4
routes:
services:
alipay: ok-cloud-service-alipay
wechatpay: ok-cloud-service-wechatpay
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
* @author yezhou
*/
@Data
@Configuration
@RefreshScope
public class RouteConfig {

@Value("${zuul.prefix}")
private String prefix;

@Bean
@ConfigurationProperties(prefix = "routes.services")
public Map<String, String> services() {
return new HashMap<>();
}

}

动态路由实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import com.alibaba.fastjson.JSON;
import com.lianlian.global.thai.provider.channel.callback.config.RouteConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;

/**
* @author yezhou
*/
@Slf4j
@Component
public class DynamicZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

private ZuulProperties properties;

@Autowired
private RouteConfig routeConfig;

public DynamicZuulRouteLocator(ServerProperties serverProperties, ZuulProperties properties) {
super(serverProperties.getServlet().getContextPath(), properties);
this.properties = properties;
}

@Override
public void refresh() {
doRefresh();
}

@Override
protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
log.info("DynamicZuulRouteLocator.locateRoutes: {}", JSON.toJSONString(routeConfig.services()));
Map<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<>();

// 静态路由信息
routesMap.putAll(super.locateRoutes());

// 动态加载路由信息
Map<String, String> services = routeConfig.services();
for (Map.Entry<String, String> entry : services.entrySet()) {
ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
zuulRoute.setId(entry.getKey());
String path = String.format("/%s/**", entry.getKey());
zuulRoute.setPath(path);
zuulRoute.setServiceId(entry.getValue());
zuulRoute.setRetryable(true);
routesMap.put(path, zuulRoute);
}

Map<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.hasText(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
return values;
}
}