最近做一個新項目,用到了Gateway
考慮到之後開發環境的的路由和線上的肯定不一緻,而且後續可能會涉及到修改和新增路由資訊
是以,動态路由是必須要上的,廢話不多說,開車!
安裝服務中心(注冊中心)Nacos
想要實作Gateway動态路由,服務中心是前置條件,在國内,現在最主流的服務中心,應該非Nacos莫屬了
沒安裝的小夥伴,參考下我的這篇文章,安裝過程非常簡單
已經安裝好了的,我們繼續往下看
pom 依賴
xml複制代碼 <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.0.5.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.0.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>3.1.6</version>
</dependency>
yml 配置檔案修改
修改前
properties複制代碼server:
port: 8080
spring:
application:
name: my-gateway
cloud:
nacos:
# IP端口和使用者名、密碼
server-addr: 127.0.0.1:8868
username: nacos
password: nacos
gateway:
routes:
- id: api
# 比對後,轉發到此域名
uri: lb://api
# 比對路徑
predicates:
- Path=/api/**
# 過濾器配置
filters:
- StripPrefix=1
修改後
但等會兒我們實作了動态 routes 之後,.yml 檔案裡 routes就沒有用了,我們可以把它注釋或者删除 大家自行參考下方配置進行修改,新增的和注釋的行,我都做有标記。
properties複制代碼server:
port: 8080
spring:
application:
name: my-gateway
cloud:
nacos:
# IP端口和使用者名、密碼
server-addr: 127.0.0.1:8868
username: nacos
password: nacos
+ config:
+ # 禁用Spring的配置導入檢查
+ import-check:
+ enabled: false
gateway:
+ discovery:
+ locator:
+ # 開啟通過服務中心動态更新配置的功能
+ enabled: true
# routes:
# - id: api
# # 比對後,轉發到此域名
# uri: lb://api
# # 比對路徑
# predicates:
# - Path=/api/**
# # 過濾器配置
# filters:
# - StripPrefix=1
監聽變更與更新路由配置
我們需要寫一點Java代碼,監聽Nacos上面的配置變更,然後更新路由資訊
java複制代碼
/**
* 路由資訊變更監聽
*/
@Component
@RefreshScope
public class OnRouteConfigChange implements ApplicationEventPublisherAware {
private static final Logger LOGGER = LoggerFactory.getLogger(OnRouteConfigChange.class);
/** 路由資訊寫入器 */
@Resource
private RouteDefinitionWriter routeDefinitionWriter;
/** 擷取yml檔案裡nacos的配置資訊 */
@Resource
private NacosConfigProperties nacosConfigProperties;
/** nacos 配置服務 */
private ConfigService configService;
/** 應用事件釋出器 */
private ApplicationEventPublisher publisher;
/**
* 擷取 nacos 配置服務
* @return
* @throws NacosException
*/
private ConfigService getConfigService() throws NacosException {
// 懶漢加載,用到再建立這個服務
if (null == configService){
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosConfigProperties.getServerAddr());
properties.setProperty(PropertyKeyConst.USERNAME, nacosConfigProperties.getUsername());
properties.setProperty(PropertyKeyConst.PASSWORD, nacosConfigProperties.getPassword());
configService = NacosFactory.createConfigService(properties);
}
return configService;
}
/**
* 網關初始化
*/
@PostConstruct
public void initGatewayRoutes() {
try {
// 配置ID
String dateId = "my_gateway_route_config";
// 分組
String group = "MY_GATEWAY_ROUTE";
// 擷取目前Nacos裡,對應dataId的配置資料,随後開始監聽對應dataId資料變更
String configJson = getConfigService().getConfigAndSignListener(dateId, group, nacosConfigProperties.getTimeout(), new Listener() {
@Override
public Executor getExecutor() { return null; }
/**
* 資料變更時觸發
* @param configInfo 新的配置資訊
*/
@Override
public void receiveConfigInfo(String configInfo) {
LoggerUtils.info(LOGGER, "監聽到網關路由配置變更:{0}", configInfo);
saveRoutesConfig(configInfo);
}
});
LoggerUtils.info(LOGGER, "初始化網關路由配置:{0}", configJson);
saveRoutesConfig(configJson);
} catch (Exception e) {
LoggerUtils.error(e, LOGGER, "初始化網關路由時發生錯誤", e);
}
}
/**
* 儲存路由配置
* @param configJson
*/
private void saveRoutesConfig(String configJson){
List<RouteDefinition> definitions = JSONArray.parseArray(configJson, RouteDefinition.class);
if (!CollectionUtils.isEmpty(definitions)){
// 周遊更新路由資訊
for (RouteDefinition definition : definitions){
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
}
// 發送重新整理路由的事件通知
publisher.publishEvent(new RefreshRoutesEvent(this));
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
publisher = applicationEventPublisher;
}
}
在 Nacos 裡配置路由資訊
打開Nacos的控制台(我的Nacos端口配置成了8868,大家自行根據自己的端口配置來通路)
http://127.0.0.1:8868/nacos/
點選【建立配置】
如下圖進行配置即可
配置内容資訊,已經貼在下方了,大家可以自行複制參考
Data ID 和 Group 其實就是上面Java代碼中的dateId和group,這裡一定要對上,不然拉取不到配置
java複制代碼 // 配置ID
String dateId = "my_gateway_route_config";
// 分組
String group = "MY_GATEWAY_ROUTE";
配置内容(JSON)
json複制代碼 [
{
"id": "api",
"uri": "lb://api",
"predicates": [
{
"args": {
"pattern": "/api/**",
},
"name": "Path"
}
],
"filters": [
{
"args": {
"parts": 1
},
"name": "StripPrefix"
}
],
"order": 1
}
]
拓展知識:
1、配置内容是根據 org.springframework.cloud.gateway.route.RouteDefinition 的字段内容
2、args 裡的内容,key名稱可以随意設定,隻要和這個args裡的其他字段不重名就可以,它就是一個Map
例如 "pattern": "/api/**" 設定成 "pattern1": "/api/**",效果是一樣的
3、args 裡,如果想設定多個條件,加字段即可
例如 "args":{"pattern1": "/api/**", "pattern2": "/apis/**"}
驗證是否成功
為了能夠比較直覺的驗證,我們重新【編輯】一下Nacos上面的配置内容
把uri改成 https://aliyun.com/,點選【釋出】
然後,運作項目
在浏覽器中輸入:http://localhost:8080/api
成功進入了 aliyun.com 阿裡雲的頁面,說明動态配置生效了
再試試改成 baidu.com ,和上面的步驟一樣,編輯->修改uri->釋出
然後重新整理頁面,和預期的一樣,進入了百度的頁面
搞定!
如果對您有幫助,請點個贊吧。
最後補充一個點
偶爾出現 gateway Failed to resolve 'xxx.com' after 5 queries 錯誤,過一會或者重新開機就好了,原因不清。
作者:大鵝coding
連結:https://juejin.cn/post/7239305332823982140