Spring Cloud 网关服务 zuul 动态路由的实现方法

网友投稿 866 2023-07-14

Spring Cloud 网关服务 zuul 动态路由的实现方法

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;

/**

* 路由实体类

*

* @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;

/**

* 服务名称

*/

PHVVVLdemDprivate String serviceId;

/**

* url代理

*/

private String url;

/**

* 转发去掉前缀

*/

private String stripPrefix;

/**

* 是否重试

*/

private String retryable;

/**

* 是否启用

*/

private String enabled;

/**

* 敏感请求头

*/

private String sensitiveheadersList;

/**

* 创建时间

*/

private Date createTime;

/**

* 更新时间

*/

private Date updateTime;

/**

* 删除标识(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-flix.zuul.filters.RefreshableRouteLocator;

import org.springframework.cloud-flix.zuul.filters.SimpleRouteLocator;

import org.springframework.cloud-flix.zuul.filters.ZuulProperties;

import org.springframework.jdbc.core.BeanPropertyRowMapper;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.util.StringUtils;

import java.util.*;

/**

*

*

* @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 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;

}

/**

* 从数据库读取zuul路由规则

* @return

*/

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-flix.zuul.RoutesRefreshedEvent;

import org.springframework.cloud-flix.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;

/**

* 路由刷新事件发布,与事件监听者

*

* @author xianliru@100tal.com

* @version 1.0

* @createDate 2019/10/30 15:27

*/

@Service

public class RefreshRouteService implements ApplicationListener {

@Autowired

private ZuulHandlerMapping zuulHandlerMapping;

private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();

@Autowired

ApplicationEventPublisher publisher;

@Autowired

private DiscoveryRouteLocator dynamicRouteLocator;

/**

* 动态路由实现 调用refreshRoute() 发布刷新路由事件

*/

public void refreshRoute() {

RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(dynamicRouteLocator);

publisher.publishEvent(routesRefreshedEvent);

}

/**

* 事件监听者。监控检测事件刷新

* @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){

//心跳触发,将本地映射关系。关联到远程服务上

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;

/**

* 手动刷新对外接口

*

* @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";

}

}

数据库表结构

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 动态网关路由完成。

总结

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:通过volatile验证线程之间的可见性
下一篇:Spring整合Weblogic jms实例详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~