天天看點

Spring Cloud Gateway 實作動态路由(超簡單版)

作者:程式猿阿嘴

最近做一個新項目,用到了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/

點選【建立配置】

Spring Cloud Gateway 實作動态路由(超簡單版)

如下圖進行配置即可

配置内容資訊,已經貼在下方了,大家可以自行複制參考

Spring Cloud Gateway 實作動态路由(超簡單版)

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

Spring Cloud Gateway 實作動态路由(超簡單版)

成功進入了 aliyun.com 阿裡雲的頁面,說明動态配置生效了

再試試改成 baidu.com ,和上面的步驟一樣,編輯->修改uri->釋出

然後重新整理頁面,和預期的一樣,進入了百度的頁面

Spring Cloud Gateway 實作動态路由(超簡單版)

搞定!

如果對您有幫助,請點個贊吧。

最後補充一個點

偶爾出現 gateway Failed to resolve 'xxx.com' after 5 queries 錯誤,過一會或者重新開機就好了,原因不清。

作者:大鵝coding

連結:https://juejin.cn/post/7239305332823982140