Spring Cloud Zuul的動態(tài)路由怎樣做压固?集成Nacos實現(xiàn)很簡單

一、說明

網(wǎng)關(guān)的核心概念就是路由配置和路由規(guī)則靠闭,而作為所有請求流量的入口帐我,在實際生產(chǎn)環(huán)境中為了保證高可靠和高可用,是盡量要避免重啟的愧膀,所以實現(xiàn)動態(tài)路由是非常有必要的焚刚;本文主要介紹實現(xiàn)的思路,并且以Nacos為數(shù)據(jù)源來講解

?

二扇调、實現(xiàn)要點

要實現(xiàn)動態(tài)路由只需關(guān)注下面4個點

  1. 網(wǎng)關(guān)啟動時矿咕,動態(tài)路由的數(shù)據(jù)怎樣加載進(jìn)來
  2. 靜態(tài)路由動態(tài)路由以那個為準(zhǔn),ps:靜態(tài)路由指的是配置文件里寫死的路由配置
  3. 監(jiān)聽動態(tài)路由的數(shù)據(jù)源變化
  4. 數(shù)據(jù)有變化時怎樣通知zuul刷新路由

?

三狼钮、具體實現(xiàn)

3.1. 實現(xiàn)動態(tài)路由的數(shù)據(jù)加載

  • 重寫SimpleRouteLocator類的locateRoutes方法碳柱,此方法是加載路由配置的,父類中是獲取properties中的路由配置熬芜,可以通過擴展此方法莲镣,達(dá)到動態(tài)獲取配置的目的
  • 這里采用靜態(tài)路由動態(tài)路由共存,相同路由id以動態(tài)路由優(yōu)先覆蓋的實現(xiàn)方式

AbstractDynRouteLocator類可查看:AbstractDynRouteLocator.java

public abstract class AbstractDynRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
    private ZuulProperties properties;

    public AbstractDynRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }

    /**
     * 刷新路由
     */
    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
        // 從application.properties中加載靜態(tài)路由信息
        routesMap.putAll(super.locateRoutes());
        // 從數(shù)據(jù)源中加載動態(tài)路由信息
        routesMap.putAll(loadDynamicRoute());
        // 優(yōu)化一下配置
        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // 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());
        }
        return values;
    }

    /**
     * 加載路由配置涎拉,由子類去實現(xiàn)
     */
    public abstract Map<String, ZuulRoute> loadDynamicRoute();
}

由于動態(tài)路由的數(shù)據(jù)可以有很多種途徑瑞侮,如:Nacos、Redis鼓拧、Zookeeper半火、DB等,所以這里定義一個抽象類季俩,由具體的實現(xiàn)類去定義loadDynamicRoute方法

?

3.2. Nacos路由實現(xiàn)類

NacosDynRouteLocator類完整的代碼實現(xiàn)可查看:NacosDynRouteLocator.java

3.2.1. 實現(xiàn)loadDynamicRoute方法獲取動態(tài)數(shù)據(jù)

    @Override
    public Map<String, ZuulProperties.ZuulRoute> loadDynamicRoute() {
        Map<String, ZuulRoute> routes = new LinkedHashMap<>();
        if (zuulRouteEntities == null) {
            zuulRouteEntities = getNacosConfig();
        }
        for (ZuulRouteEntity result : zuulRouteEntities) {
            if (StrUtil.isBlank(result.getPath()) || !result.isEnabled()) {
                continue;
            }
            ZuulRoute zuulRoute = new ZuulRoute();
            BeanUtil.copyProperties(result, zuulRoute);
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        return routes;
    }
        
    private List<ZuulRouteEntity> getNacosConfig() {
        try {
            String content = nacosConfigProperties.configServiceInstance().getConfig(ZUUL_DATA_ID, ZUUL_GROUP_ID,5000);
            return getListByStr(content);
        } catch (NacosException e) {
            log.error("listenerNacos-error", e);
        }
        return new ArrayList<>(0);
    }

3.2.2. 增加NacosListener監(jiān)聽路由數(shù)據(jù)變化

    private void addListener() {
        try {
            nacosConfigProperties.configServiceInstance().addListener(ZUUL_DATA_ID, ZUUL_GROUP_ID, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    //賦值路由信息
                    locator.setZuulRouteEntities(getListByStr(configInfo));
                    RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(locator);
                    publisher.publishEvent(routesRefreshedEvent);
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

注意路由數(shù)據(jù)變化后不需要自己手動刷新路由钮糖,只需要給zuul發(fā)送一個RoutesRefreshedEvent事件即可,zuul自己有個ZuulRefreshListener類會監(jiān)聽事件幫我們刷新路由

?

3.3. 配置類創(chuàng)建NacosDynRouteLocator的Bean

DynamicZuulRouteConfig可查看:NacosDynRouteLocator.java

@Configuration
@ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "enabled", havingValue = "true")
public class DynamicZuulRouteConfig {
    @Autowired
    private ZuulProperties zuulProperties;

    @Autowired
    private DispatcherServletPath dispatcherServletPath;

    /**
     * Nacos實現(xiàn)方式
     */
    @Configuration
    @ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "dataType", havingValue = "nacos", matchIfMissing = true)
    public class NacosZuulRoute {
        @Autowired
        private NacosConfigProperties nacosConfigProperties;

        @Autowired
        private ApplicationEventPublisher publisher;

        @Bean
        public NacosDynRouteLocator nacosDynRouteLocator() {
            return new NacosDynRouteLocator(nacosConfigProperties, publisher, dispatcherServletPath.getPrefix(), zuulProperties);
        }
    }
}

這里通過自定義配置來控制是否開啟動態(tài)路由功能

?

3.4. 添加Nacos路由配置

file

新增配置項:

  • Data Id:zuul-routes
  • Group:ZUUL_GATEWAY
  • 配置內(nèi)容:
[
    {
        "enabled":true,
        "id":"csdn",
        "path":"/csdn/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"https://www.csdn.net/"
    }, {
        "enabled":true,
        "id":"github",
        "path":"/github/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"http://github.com/"
    }
]

添加兩條路由數(shù)據(jù)

?

四酌住、測試

  • 啟動網(wǎng)關(guān)通過/actuator/routes端點查看當(dāng)前路由信息
    file

可以看到靜態(tài)路由和Nacos里配置的兩條路由信息并存顯示

  • 修改Nacos配置店归,關(guān)閉csdn路由
    file
  • 刷新查看網(wǎng)關(guān)的路由信息
    file

csdn的路由已經(jīng)看不到了韭赘,實現(xiàn)了動態(tài)改變路由配置

?
推薦閱讀

?
請掃碼關(guān)注我的公眾號

file

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茎芋,一起剝皮案震驚了整個濱河市把沼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秩伞,老刑警劉巖谴古,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稠歉,居然都是意外死亡,警方通過查閱死者的電腦和手機汇陆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門怒炸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人毡代,你說我怎么就攤上這事阅羹。” “怎么了教寂?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵捏鱼,是天一觀的道長。 經(jīng)常有香客問我酪耕,道長导梆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任迂烁,我火速辦了婚禮看尼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盟步。我一直安慰自己藏斩,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布却盘。 她就那樣靜靜地躺著狰域,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黄橘。 梳的紋絲不亂的頭發(fā)上兆览,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音塞关,去河邊找鬼拓颓。 笑死,一個胖子當(dāng)著我的面吹牛描孟,可吹牛的內(nèi)容都是我干的驶睦。 我是一名探鬼主播砰左,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼场航!你這毒婦竟也來了缠导?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤溉痢,失蹤者是張志新(化名)和其女友劉穎僻造,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孩饼,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡髓削,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了镀娶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片立膛。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖梯码,靈堂內(nèi)的尸體忽然破棺而出宝泵,到底是詐尸還是另有隱情,我是刑警寧澤轩娶,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布儿奶,位于F島的核電站,受9級特大地震影響鳄抒,放射性物質(zhì)發(fā)生泄漏闯捎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一许溅、第九天 我趴在偏房一處隱蔽的房頂上張望隙券。 院中可真熱鬧,春花似錦闹司、人聲如沸娱仔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牲迫。三九已至,卻和暖如春借卧,著一層夾襖步出監(jiān)牢的瞬間盹憎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工铐刘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陪每,地道東北人。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像檩禾,于是被迫代替她去往敵國和親挂签。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容