现在的位置: 首页 > 编程语言 > 正文

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

2020年02月13日 编程语言 ⁄ 共 8302字 ⁄ 字号 评论关闭

zuul动态路由

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

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

DiscoveryClientRouteLocator

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

//重新加载路由信息方法 protected方法。需要子方法重新方法。protected LinkedHashMap<String, ZuulRoute> locateRoutes()//触发刷新的方法 RefreshableRouteLocator 接口 public void refresh() { this.doRefresh(); }

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

进行具体的实现

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

<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 */@Datapublic class ZuulRouteEntity implements Serializable { private static final long serialVersionUID = 1L; /** * router Id */ private Integer id; /** * 路由路径 */ private String path; /** * 服务名称 */ private 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.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 */@Slf4jpublic 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()); //优化一下配置 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; } /** * 从数据库读取zuul路由规则 * @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("数据库加载配置异常", 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;/** * <Description> 路由刷新事件发布,与事件监听者 * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/30 15:27 */@Servicepublic class RefreshRouteService implements ApplicationListener<ApplicationEvent> { @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;/** * <Description> 手动刷新对外接口 * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/30 20:23 */@RestControllerpublic 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-client2019-10-30 20:49:40.397 INFO 63449 --- [TaskScheduler-1] c.xian.cloud.router.DynamicRouteLocator : 添加数据库自定义的路由配置,path:/client/**,serviceId:cloud-discovery-clientpostman 请求client 接口 看看是否能转发成功

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

总结

以上所述是小编给大家介绍的Spring Cloud 网关服务 zuul 动态路由的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

本文标题: Spring Cloud 网关服务 zuul 动态路由的实现方法

以上就上有关SpringCloud网关服务zuul动态路由的实现方法的相关介绍,要了解更多zuul动态路由,Spring,Cloud,网关服务,Spring,Cloud,zuul内容请登录学步园。

抱歉!评论已关闭.