栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

Spring Cloud 网关服务 zuul 三 动态路由

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Cloud 网关服务 zuul 三 动态路由

zuul动态路由

网关服务是流量的唯一入口。不能随便停服务。所以动态路由就显得尤为必要。

数据库动态路由基于事件刷新机制热修改zuul的路由属性。

DiscoveryClientRouteLocator

可以看到DiscoveryClientRouteLocator 是默认的刷新的核心处理类。

//重新加载路由信息方法 protected方法。需要子方法重新方法。
protected linkedHashMap locateRoutes() 

//触发刷新的方法  RefreshableRouteLocator 接口
 public void refresh() {
			this.doRefresh();
	}

而这俩个方法都是继承与SimpleRouteLocator 类,并进行了重新操作。其实官方的方法注释说明了。如果需要动态读取加载映射关系。则需要子类重写这俩个方法。
进行具体的实现

首先pom jar包导入 需要连接mysql 数据库

 
     mysql
     mysql-connector-java
 

 
 
     org.springframework.boot
     spring-boot-starter-jdbc
 

路由实体 ZuulRouteEntity

package com.xian.cloud.entity;

import lombok.Data;

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


@Data
public class ZuulRouteEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    
    private Integer id;
    
    private String path;
    
    private String serviceId;
    
    private String url;
    
    private String stripPrefix;
    
    private String retryable;
    
    private String enabled;
    
    private String sensitiveheadersList;
    
    private Date createTime;
    
    private Date updateTime;
    
    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.*;


@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 locateRoutes() {
 linkedHashMap routesMap = new linkedHashMap();
 //从配置文件中加载路由信息
 routesMap.putAll(super.locateRoutes());
 //自定义加载路由信息
 routesMap.putAll(getRouteList());
 //优化一下配置
 linkedHashMap values = new linkedHashMap<>();
 for (Map.Entry 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;
    }

    
   private linkedHashMap getRouteList() {
 linkedHashMap zuulRoutes = new linkedHashMap<>();
 List 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 sensitiveHeadersList = Arrays.asList(route.getSensitiveheadersList().split(","));
 if (sensitiveHeadersList != null) {
     Set sensitiveHeaderSet = Sets.newHashSet();
     sensitiveHeadersList.forEach(sensitiveHeader -> sensitiveHeaderSet.add(sensitiveHeader));
     zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
     zuulRoute.setCustomSensitiveHeaders(true);
 }
    } catch (Exception e) {
 log.error("数据库加载配置异常", e);
    }
    log.info("自定义的路由配置,path:{},serviceId:{}", zuulRoute.getPath(), zuulRoute.getServiceId());
    zuulRoutes.put(zuulRoute.getPath(), zuulRoute);

}
 return zuulRoutes;
   }
}

我们还需要一个事件的生产者 和 消费者 直接图方便 集成到一个类中

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;


@Service
public class RefreshRouteService implements ApplicationListener {

    @Autowired
    private ZuulHandlerMapping zuulHandlerMapping;

    private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();

    @Autowired
    ApplicationEventPublisher publisher;

    @Autowired
    private DiscoveryRouteLocator dynamicRouteLocator;

    
    public void refreshRoute() {
 RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(dynamicRouteLocator);
 publisher.publishEvent(routesRefreshedEvent);
    }

    
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
 if(event instanceof ContextRefreshedEvent || event instanceof RefreshScopeRefreshedEvent || event instanceof RoutesRefreshedEvent){
     //主动手动刷新。上下文刷新,配置属性刷新
     zuulHandlerMapping.setDirty(true);
 }else if(event instanceof HeartbeatEvent){
     //心跳触发,将本地映射关系。关联到远程服务上
     HeartbeatEvent heartbeatEvent = (HeartbeatEvent)event;
     if(heartbeatMonitor.update(heartbeatEvent.getValue())){
  zuulHandlerMapping.setDirty(true);
     }
 }
    }
}

对外提供触发接口

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;


@RestController
public class RefreshController {

    @Autowired
    private RefreshRouteService refreshRouteService;

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

}

数据库表结构

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 '服务名称',
  `url` varchar(255) DEFAULT NULL COMMENT 'url代理',
  `strip_prefix` char(1) DEFAULT '1' COMMENT '转发去掉前缀',
  `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 '创建时间',
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标识(0-正常,1-删除)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='动态路由配置表'

将配置文件client 消费者服务 路由配置注释掉。设置数据源。从数据库中读取

启动服务打印日志

2019-10-30 20:49:39.946  INFO 63449 --- [TaskScheduler-1] c.xian.cloud.router.DynamicRouteLocator  : 添加数据库自定义的路由配置,path:/client/**,serviceId:cloud-discovery-client
2019-10-30 20:49:40.397  INFO 63449 --- [TaskScheduler-1] c.xian.cloud.router.DynamicRouteLocator  : 添加数据库自定义的路由配置,path:/client/**,serviceId:cloud-discovery-client

postman 请求client 接口 看看是否能转发成功

基于zuul 动态网关路由完成。

后续还会更新网关的灰度方案、swagger2 整合的调试源服务。敬请期待!

摘自参考 spring cloud 官方文档

参考书籍 重新定义spring cloud实战

示例代码地址

服务器nacos 地址 http://47.99.209.72:8848/nacos

往期地址 spring cloud alibaba 地址

spring cloud alibaba 简介

Spring Cloud Alibaba (nacos 注册中心搭建)

Spring Cloud Alibaba 使用nacos 注册中心

Spring Cloud Alibaba nacos 配置中心使用

spring cloud 网关服务

Spring Cloud zuul网关服务 一

Spring Cloud 网关服务 zuul 二

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。转载请附带公众号二维码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/234846.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号