网关基本配置说明
TODO:
配置URL
zuul:
routes:
users:
path: /baidu/**
url: http://baidu.com
配置微服务
zuul:
routes:
users:
path: /myusers/**
serviceId: users_service
基于Nacos实现动态路由
参考文档
https://blog.csdn.net/rickiyeat/article/details/84595350
原理:
由于Nacos支持动态配置,因此可以通过Nacos配置Zuul的路由。
- 监听nacos配置变化
public void registerNacosConfig(String dataId, String group) {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, GatewayConfig.getInstance().getNacosAddr());
ConfigService configService = NacosFactory.createConfigService(properties);
// 注册Nacos配置更新监听器,用于监听触发
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
// 发送路由刷新事件
refreshRoute();
}
@Override
public Executor getExecutor() {
return null;
}
});
} catch (NacosException e) {
e.printStackTrace();
}
}
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
SpringContextHolder.getApplicationContext().publishEvent(routesRefreshedEvent);
}
2.注册Nacos配置源
@Configuration
public class NacosZuulConfig {
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private ServerProperties serverProperties;
@Bean
public NacosZuulRouteLocator routeLocator() {
NacosZuulRouteLocator routeLocator = new NacosZuulRouteLocator(
this.serverProperties.getServlet().getServletPrefix(), this.zuulProperties);
RefreshRouteManager.getManager().setRouteLocator(routeLocator);
return routeLocator;
}
}
3.实现Nacos自动刷新接口
public class NacosZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
@Autowired
private ZuulProperties properties;
@Autowired
private DynamicNacosConfig propertiesAssemble;
public NacosZuulRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
}
@Override
public void refresh() {
super.doRefresh();
}
@Override
protected Map<String, ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
// 从application.properties中加载路由信息
routesMap.putAll(super.locateRoutes());
// 从Nacos中加载路由信息
routesMap.putAll(propertiesAssemble.getProperties());
// 优化一下配置
LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
if(path==null){
continue;
}
// Prepend with slash if not already present.
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());
}
System.out.println("Router : " + values.toString());
return values;
}
}
4.解析Nacos配置文件
@Component
public class DynamicNacosConfig {
public Map<String, ZuulRoute> getProperties() {
Map<String, ZuulRoute> routes = new LinkedHashMap<>();
if (GatewayConfig.getInstance().getDataId() == null) {
return routes;
}
List<ZuulRouteEntity> results = listenNacos(GatewayConfig.getInstance().getDataId(),
GatewayConfig.getInstance().getGroup());
for (ZuulRouteEntity result : results) {
if (StringUtils.isBlank(result.getPath())) {
continue;
}
ZuulRoute zuulRoute = new ZuulRoute(result.getId(), result.getPath(), result.getServiceId(),
result.getUrl(), result.isStripPrefix(), result.getRetryable(), null);
routes.put(zuulRoute.getPath(), zuulRoute);
}
return routes;
}
private List<ZuulRouteEntity> listenNacos(String dataId, String group) {
try {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, GatewayConfig.getInstance().getNacosAddr());
ConfigService configService = NacosFactory.createConfigService(properties);
String content = configService.getConfig(dataId, group, 5000);
System.out.println("从Nacos返回的配置:" + content);
if (content == null) {
return new ArrayList<ZuulRouteEntity>();
} else {
return JSONObject.parseArray(content, ZuulRouteEntity.class);
}
} catch (NacosException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
}
5.Nacos配置项解析Bean
public class ZuulRouteEntity {
/**
* The ID of the route (the same as its map key by default).
*/
private String id;
/**
* The path (pattern) for the route, e.g. /foo/**.
*/
private String path;
/**
* The service ID (if any) to map to this route. You can specify a physical
* URL or a service, but not both.
*/
private String serviceId;
/**
* A full physical URL to map to the route. An alternative is to use a
* service ID and service discovery to find the physical address.
*/
private String url;
/**
* Flag to determine whether the prefix for this route (the path, minus
* pattern patcher) should be stripped before forwarding.
*/
private boolean stripPrefix = true;
/**
* Flag to indicate that this route should be retryable (if supported).
* Generally retry requires a service ID and ribbon.
*/
private Boolean retryable;
private String apiName;
private Boolean enabled;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isStripPrefix() {
return stripPrefix;
}
public void setStripPrefix(boolean stripPrefix) {
this.stripPrefix = stripPrefix;
}
public Boolean getRetryable() {
return retryable;
}
public void setRetryable(Boolean retryable) {
this.retryable = retryable;
}
public String getApiName() {
return apiName;
}
public void setApiName(String apiName) {
this.apiName = apiName;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
}
Nacos配置样例
[
{"enabled":true,
"id":"test",
"path":"/test130/**",
"retryable":false,
"stripPrefix":true,
"service-id": "user-center"
}
]
授权使用说明
TODO: