每个公司项目的情况都不一样,我这个只适用于zuul
然后我是根据配置文件去动态刷新路由的,看过网上另一个教程
https://blog.csdn.net/u013815546/article/details/68944039
一些相关知识可以了解一下,我就不做赘述了,大家可以先去看一下,了解一下基础的东西, 他的教程只适用于已存在的路由进行更新, 但是相关知识的介绍还是可以看看的
具体原因可以看 locateRoutes 方法,通过这个方法获取路由信息
protected Map<String, ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap();
Iterator var2 = this.properties.getRoutes().values().iterator();
while(var2.hasNext()) {
ZuulRoute route = (ZuulRoute)var2.next();
routesMap.put(route.getPath(), route);
}
return routesMap;
}
这是新增一个LinkedHashMap给用户, 所以往里面新增路由信息时,zuul是不会增加路由信息的,这就是他的动态路由的只能刷新部分路由的原因
接下来开始讲解我的方法,我是根据远端的配置文件实时更新路由信息的,大家可以根据自己的情况选择数据库或者其它之类的进行修改
创建 DynamicZuulConfig ,主要是为了实时获取路由信息, 关键注解 @RefreshScope , 用于刷新配置信息,具体作用自行度娘
package com.xxx.gate.customer.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Data
@RefreshScope
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "developer")
public class DynamicZuulConfig {
private boolean flag; // 标识刷新的flag
private List<String> names;
private List<String> gate-x; // 需要做动态路由的网关名称
}
创建 DynamicZuulConfiguration 用于将一些Bean对象注入到动态路由加载器中,
这边routeLocator方法加RefreshScope 注解是为了提醒zuul加载器,配置文件更新了, 参考 ↓
https://www.cnblogs.com/yjmyzz/p/8085530.html
package com.xxx.gate.customer.config;
import com.xxx.gate.customer.locator.DynamicRouteLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DynamicZuulConfiguration {
@Autowired
private DynamicZuulConfig developerNamesConfig; // 动态路由信息配置文件
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private ServerProperties server;
@Bean
@RefreshScope //关键注解
public DynamicRouteLocator routeLocator() {
DynamicRouteLocator routeLocator =
new DynamicRouteLocator(this.server.getServletPrefix(), this.zuulProperties, this.developerNamesConfig);
return routeLocator;
}
}
创建 DynamicRouteLocator 并继承 SimpleRouteLocator 和实现 RefreshableRouteLocator 接口
这才是主要的zuul加载路由信息的实现方法
private void locateRoutesRefresh用于封装动态路由信息, 关键是最后一句, 将路由信息重新设置到 ZuulProperties 中
properties.setRoutes(routeMap);
package com.xxx.gate.customer.locator;
import com.xxx.gate.customer.config.DynamicZuulConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import java.util.List;
import java.util.Map;
public class DynamicRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
private static Logger logger = LoggerFactory.getLogger(DynamicRouteLocator.class);
private DynamicZuulConfig developerNamesConfig;
private ZuulProperties properties;
public DynamicRouteLocator(String servletPath, ZuulProperties properties, DynamicZuulConfig developerNamesConfig) {
super(servletPath, properties);
this.properties = properties;
this.developerNamesConfig = developerNamesConfig;
}
@Override
public void refresh() {
doRefresh();
}
@Override
protected Map<String, ZuulRoute> locateRoutes() {
// 从application.properties中加载路由信息
Map<String, ZuulRoute> routeMap = properties.getRoutes();
// 重新加载动态配置中信息
locateRoutesRefresh(routeMap);
return routeMap;
}
/**
* 修改路由对象信息
*/
private void locateRoutesRefresh(Map<String, ZuulRoute> routeMap) {
if (null == developerNamesConfig || !developerNamesConfig.isFlag() || developerNamesConfig.getGate-X().isEmpty() || developerNamesConfig.getNames().isEmpty()) {
return;
}
List<String> keys = developerNamesConfig.getGate-X();
List<String> names = developerNamesConfig.getNames();
keys.forEach(key ->
names.forEach(name -> {
String id = key + "_" + name;
String path = "/" + id + "/**";
String serviceId = id.replaceAll("_", "-");
ZuulRoute zuulRoute = routeMap.get(path);
if (null == zuulRoute) {
zuulRoute = new ZuulRoute();
}
zuulRoute.setId(id);
zuulRoute.setPath(path);
zuulRoute.setServiceId(serviceId);
zuulRoute.setStripPrefix(true);
routeMap.put(path, zuulRoute);
})
);
properties.setRoutes(routeMap); //关键步骤,将路由信息重新设置到ZuulProperties中
developerNamesConfig.setFlag(false); //将更新标识设置为false
}
}
以上就是所有代码,接下来讲解配置文件
在远端配置git上创建common_developer.yml 用于填写动态信息, 因为locateRoutes 方法会被一直调用,所以需要使用flag来标识需要更新路由信息,否则会一直重复对路由赋值
# 开发环境动态路由配置信息
developer:
flag: true # 标识需要更新
gate-a: # 网关A
- a_microservice # a微服务
- b_microservice # b微服务
- c_microservice # c微服务
gate-b: # 网关B
- d_microservice # d微服务
- e_microservice # e微服务
gate-c: # 网关C
- f_microservice # f微服务
names:
- zhangsan # 开发人员张三
- lisi # 开发人员李四
- wangwu #开发人员王五
这边可以针对每个网关都写一个配置文件,也可以针对所有网关和微服务写一个公共的配置文件
接下来是生成的格式
zuul路由关键属性是 id, path, serviceId, StripPrefix属性, 分别对应以下属性
id: zuul.routes.xxx
path: zuul.routes.xxx.path // url路径
serviceId: zuul.routes.xxx.serviceId // 对应spring.application.name属性
StripPrefix: 默认为true
所以在设置spring.application.name 属性时最好和id, path, serviceId 统一
比如xxx-microservice,这样生成格式就是
zuul:
routes:
xxx_microservice:
path: /xxx_microservice/**
serviceId: xxx-microservice
# 下面是动态路由生成的结构
xxx_microservice_zhangsan:
path: /xxx_microservice_zhangsan/**
serviceId: xxx-microservice-zhangsan
这样就不用做多余的兼容代码了
要使用RefreshScope 需要引入下面的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后在配置文件中加入下面的配置, 这是为了在调用refresh接口时忽略安全校验(好像是这个...),否则就无法触发@RefreshScope
management:
security:
enabled: false
最后就是通过webhooks功能实现远端配置文件更新时请求springcloud的refresh接口, 我这边用的是公司内部的gitlab
进入项目,然后在左侧选择 Setting -> integrations
URL 就是请求的地址,默认使用POST请求, 输入http://ip:port/refresh ,然后 Add webhook, 就可以添加了
之后每次更新配置中心文件时, 就会去post 网关的/rerfesh接口,然后刷新配置信息
如果帮到你,请点个赞吧 O(∩_∩)O~