如何實現(xiàn)zuul動態(tài)路由

本篇內(nèi)容介紹了“如何實現(xiàn)zuul動態(tài)路由”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的微山網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

zuul動態(tài)路由

網(wǎng)關(guān)服務(wù)是流量的唯一入口。不能隨便停服務(wù)。所以動態(tài)路由就顯得尤為必要。

數(shù)據(jù)庫動態(tài)路由基于事件刷新機制熱修改zuul的路由屬性。

DiscoveryClientRouteLocator

如何實現(xiàn)zuul動態(tài)路由

可以看到DiscoveryClientRouteLocator 是默認(rèn)的刷新的核心處理類。

//重新加載路由信息方法 protected方法。需要子方法重新方法。
protected LinkedHashMap<String, ZuulRoute> locateRoutes() 

//觸發(fā)刷新的方法  RefreshableRouteLocator 接口
 public void refresh() {
			this.doRefresh();
	}

而這倆個方法都是繼承與SimpleRouteLocator 類,并進(jìn)行了重新操作。其實官方的方法注釋說明了。如果需要動態(tài)讀取加載映射關(guān)系。則需要子類重寫這倆個方法。 進(jìn)行具體的實現(xiàn)

首先pom jar包導(dǎo)入 需要連接MySQL 數(shù)據(jù)庫

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

路由實體 ZuulRouteEntity

package com.xian.cloud.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * <Description> 路由實體類
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/10/30 15:00
 */
@Data
public class ZuulRouteEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * router Id
     */
    private Integer id;
    /**
     * 路由路徑
     */
    private String path;
    /**
     * 服務(wù)名稱
     */
    private String serviceId;
    /**
     * url代理
     */
    private String url;
    /**
     * 轉(zhuǎn)發(fā)去掉前綴
     */
    private String stripPrefix;
    /**
     * 是否重試
     */
    private String retryable;
    /**
     * 是否啟用
     */
    private String enabled;
    /**
     * 敏感請求頭
     */
    private String sensitiveheadersList;
    /**
     * 創(chuàng)建時間
     */
    private Date createTime;
    /**
     * 更新時間
     */
    private Date updateTime;
    /**
     * 刪除標(biāo)識(0-正常,1-刪除)
     */
    private String delFlag;
}

新建DiscoveryRouteLocator 類 父類 接口 都不變化

package com.xian.cloud.router;


import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.xian.cloud.entity.ZuulRoute;
import lombok.extern.slf4j.Slf4j;
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.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * <Description>
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/10/30 18:57
 */
@Slf4j
public class DiscoveryRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    private ZuulProperties properties;

    private JdbcTemplate jdbcTemplate;

    public DiscoveryRouteLocator(String servletPath, ZuulProperties properties, JdbcTemplate jdbcTemplate) {
        super(servletPath, properties);
        this.properties = properties;
        this.jdbcTemplate = jdbcTemplate;
        log.info("servletPath:{}",servletPath);
    }

    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
        //從配置文件中加載路由信息
        routesMap.putAll(super.locateRoutes());
        //自定義加載路由信息
        routesMap.putAll(getRouteList());
        //優(yōu)化一下配置
        LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulProperties.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;
    }

    /**
     * 從數(shù)據(jù)庫讀取zuul路由規(guī)則
     * @return
     */
   private LinkedHashMap<String, ZuulProperties.ZuulRoute> getRouteList() {
        LinkedHashMap<String, ZuulProperties.ZuulRoute> zuulRoutes = new LinkedHashMap<>();
        List<ZuulRoute> sysZuulRoutes = jdbcTemplate.query("select * from sys_zuul_route where del_flag = 0", new BeanPropertyRowMapper<>(ZuulRoute.class));

       for (ZuulRoute route: sysZuulRoutes) {

           // 為空跳過
           if (Strings.isNullOrEmpty(route.getPath()) && Strings.isNullOrEmpty(route.getUrl())) {
               continue;
           }

           ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
           try {
               zuulRoute.setId(route.getServiceId());
               zuulRoute.setPath(route.getPath());
               zuulRoute.setServiceId(route.getServiceId());
               zuulRoute.setRetryable(Objects.equals("0", route.getRetryable()) ? Boolean.FALSE : Boolean.TRUE);
               zuulRoute.setStripPrefix(Objects.equals("0", route.getStripPrefix()) ? Boolean.FALSE : Boolean.TRUE);
               zuulRoute.setUrl(route.getUrl());
               List<String> sensitiveHeadersList = Arrays.asList(route.getSensitiveheadersList().split(","));
               if (sensitiveHeadersList != null) {
                   Set<String> sensitiveHeaderSet = Sets.newHashSet();
                   sensitiveHeadersList.forEach(sensitiveHeader -> sensitiveHeaderSet.add(sensitiveHeader));
                   zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
                   zuulRoute.setCustomSensitiveHeaders(true);
               }
           } catch (Exception e) {
               log.error("數(shù)據(jù)庫加載配置異常", e);
           }
           log.info("自定義的路由配置,path:{},serviceId:{}", zuulRoute.getPath(), zuulRoute.getServiceId());
           zuulRoutes.put(zuulRoute.getPath(), zuulRoute);

       }
        return zuulRoutes;
   }
}

我們還需要一個事件的生產(chǎn)者 和 消費者 直接圖方便 集成到一個類中

package com.xian.cloud.event;

import com.xian.cloud.router.DiscoveryRouteLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
import org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;

/**
 * <Description> 路由刷新事件發(fā)布,與事件監(jiān)聽者
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/10/30 15:27
 */
@Service
public class RefreshRouteService implements ApplicationListener<ApplicationEvent> {

    @Autowired
    private ZuulHandlerMapping zuulHandlerMapping;

    private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();

    @Autowired
    ApplicationEventPublisher publisher;

    @Autowired
    private DiscoveryRouteLocator dynamicRouteLocator;

    /**
     * 動態(tài)路由實現(xiàn) 調(diào)用refreshRoute() 發(fā)布刷新路由事件
     */
    public void refreshRoute() {
        RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(dynamicRouteLocator);
        publisher.publishEvent(routesRefreshedEvent);
    }

    /**
     * 事件監(jiān)聽者。監(jiān)控檢測事件刷新
     * @param event
     */
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ContextRefreshedEvent || event instanceof RefreshScopeRefreshedEvent || event instanceof RoutesRefreshedEvent){
            //主動手動刷新。上下文刷新,配置屬性刷新
            zuulHandlerMapping.setDirty(true);
        }else if(event instanceof HeartbeatEvent){
            //心跳觸發(fā),將本地映射關(guān)系。關(guān)聯(lián)到遠(yuǎn)程服務(wù)上
            HeartbeatEvent heartbeatEvent = (HeartbeatEvent)event;
            if(heartbeatMonitor.update(heartbeatEvent.getValue())){
                zuulHandlerMapping.setDirty(true);
            }
        }
    }
}

對外提供觸發(fā)接口

package com.xian.cloud.controller;

import com.xian.cloud.event.RefreshRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <Description> 手動刷新對外接口
 *
 * @author xianliru@100tal.com
 * @version 1.0
 * @createDate 2019/10/30 20:23
 */
@RestController
public class RefreshController {

    @Autowired
    private RefreshRouteService refreshRouteService;

    @GetMapping("/refresh")
    public String refresh() {
        refreshRouteService.refreshRoute();
        return "refresh";
    }

}

數(shù)據(jù)庫表結(jié)構(gòu)

CREATE TABLE `sys_zuul_route` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'router Id',
  `path` varchar(255) NOT NULL COMMENT '路由路徑',
  `service_id` varchar(255) NOT NULL COMMENT '服務(wù)名稱',
  `url` varchar(255) DEFAULT NULL COMMENT 'url代理',
  `strip_prefix` char(1) DEFAULT '1' COMMENT '轉(zhuǎn)發(fā)去掉前綴',
  `retryable` char(1) DEFAULT '1' COMMENT '是否重試',
  `enabled` char(1) DEFAULT '1' COMMENT '是否啟用',
  `sensitiveHeaders_list` varchar(255) DEFAULT NULL COMMENT '敏感請求頭',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  `del_flag` char(1) DEFAULT '0' COMMENT '刪除標(biāo)識(0-正常,1-刪除)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='動態(tài)路由配置表'

如何實現(xiàn)zuul動態(tài)路由

將配置文件client 消費者服務(wù) 路由配置注釋掉。設(shè)置數(shù)據(jù)源。從數(shù)據(jù)庫中讀取

如何實現(xiàn)zuul動態(tài)路由

啟動服務(wù)打印日志

2019-10-30 20:49:39.946  INFO 63449 --- [TaskScheduler-1] c.xian.cloud.router.DynamicRouteLocator  : 添加數(shù)據(jù)庫自定義的路由配置,path:/client/**,serviceId:cloud-discovery-client
2019-10-30 20:49:40.397  INFO 63449 --- [TaskScheduler-1] c.xian.cloud.router.DynamicRouteLocator  : 添加數(shù)據(jù)庫自定義的路由配置,path:/client/**,serviceId:cloud-discovery-client

postman 請求client 接口 看看是否能轉(zhuǎn)發(fā)成功 如何實現(xiàn)zuul動態(tài)路由

基于zuul 動態(tài)網(wǎng)關(guān)路由完成。

“如何實現(xiàn)zuul動態(tài)路由”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

網(wǎng)站欄目:如何實現(xiàn)zuul動態(tài)路由
文章鏈接:http://muchs.cn/article40/jpipho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、關(guān)鍵詞優(yōu)化網(wǎng)站建設(shè)、電子商務(wù)、全網(wǎng)營銷推廣App設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司