Spring Cloud 网关服务 zuul 动态路由的实现方法
zuul动态路由
网关服务是流量的唯一入口。不能随便停服务。所以动态路由就显得尤为必要。
数据库动态路由基于事件刷新机制热修改zuul的路由属性。
DiscoveryClientRouteLocator
可以看到DiscoveryClientRouteLocator是默认的刷新的核心处理类。
//重新加载路由信息方法protected方法。需要子方法重新方法。 protectedLinkedHashMaplocateRoutes() //触发刷新的方法RefreshableRouteLocator接口 publicvoidrefresh(){ this.doRefresh(); }
而这俩个方法都是继承与SimpleRouteLocator类,并进行了重新操作。其实官方的方法注释说明了。如果需要动态读取加载映射关系。则需要子类重写这俩个方法。
进行具体的实现
首先pomjar包导入需要连接mysql数据库
mysql mysql-connector-java org.springframework.boot spring-boot-starter-jdbc
路由实体ZuulRouteEntity
packagecom.xian.cloud.entity; importlombok.Data; importjava.io.Serializable; importjava.util.Date; /** *路由实体类 * *@authorxianliru@100tal.com *@version1.0 *@createDate2019/10/3015:00 */ @Data publicclassZuulRouteEntityimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; /** *routerId */ privateIntegerid; /** *路由路径 */ privateStringpath; /** *服务名称 */ privateStringserviceId; /** *url代理 */ privateStringurl; /** *转发去掉前缀 */ privateStringstripPrefix; /** *是否重试 */ privateStringretryable; /** *是否启用 */ privateStringenabled; /** *敏感请求头 */ privateStringsensitiveheadersList; /** *创建时间 */ privateDatecreateTime; /** *更新时间 */ privateDateupdateTime; /** *删除标识(0-正常,1-删除) */ privateStringdelFlag; }
新建DiscoveryRouteLocator类父类接口都不变化
packagecom.xian.cloud.router; importcom.google.common.base.Strings; importcom.google.common.collect.Sets; importcom.xian.cloud.entity.ZuulRoute; importlombok.extern.slf4j.Slf4j; importorg.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator; importorg.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator; importorg.springframework.cloud.netflix.zuul.filters.ZuulProperties; importorg.springframework.jdbc.core.BeanPropertyRowMapper; importorg.springframework.jdbc.core.JdbcTemplate; importorg.springframework.util.StringUtils; importjava.util.*; /** ** *@authorxianliru@100tal.com *@version1.0 *@createDate2019/10/3018:57 */ @Slf4j publicclassDiscoveryRouteLocatorextendsSimpleRouteLocatorimplementsRefreshableRouteLocator{ privateZuulPropertiesproperties; privateJdbcTemplatejdbcTemplate; publicDiscoveryRouteLocator(StringservletPath,ZuulPropertiesproperties,JdbcTemplatejdbcTemplate){ super(servletPath,properties); this.properties=properties; this.jdbcTemplate=jdbcTemplate; log.info("servletPath:{}",servletPath); } @Override publicvoidrefresh(){ doRefresh(); } @Override protectedMap locateRoutes(){ LinkedHashMap routesMap=newLinkedHashMap (); //从配置文件中加载路由信息 routesMap.putAll(super.locateRoutes()); //自定义加载路由信息 routesMap.putAll(getRouteList()); //优化一下配置 LinkedHashMap values=newLinkedHashMap<>(); for(Map.Entry entry:routesMap.entrySet()){ Stringpath=entry.getKey(); //Prependwithslashifnotalreadypresent. 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()); } returnvalues; } /** *从数据库读取zuul路由规则 *@return */ privateLinkedHashMap getRouteList(){ LinkedHashMap zuulRoutes=newLinkedHashMap<>(); List sysZuulRoutes=jdbcTemplate.query("select*fromsys_zuul_routewheredel_flag=0",newBeanPropertyRowMapper<>(ZuulRoute.class)); for(ZuulRouteroute:sysZuulRoutes){ //为空跳过 if(Strings.isNullOrEmpty(route.getPath())&&Strings.isNullOrEmpty(route.getUrl())){ continue; } ZuulProperties.ZuulRoutezuulRoute=newZuulProperties.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(Exceptione){ log.error("数据库加载配置异常",e); } log.info("自定义的路由配置,path:{},serviceId:{}",zuulRoute.getPath(),zuulRoute.getServiceId()); zuulRoutes.put(zuulRoute.getPath(),zuulRoute); } returnzuulRoutes; } }
我们还需要一个事件的生产者和消费者直接图方便集成到一个类中
packagecom.xian.cloud.event; importcom.xian.cloud.router.DiscoveryRouteLocator; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.cloud.client.discovery.event.HeartbeatEvent; importorg.springframework.cloud.client.discovery.event.HeartbeatMonitor; importorg.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; importorg.springframework.cloud.netflix.zuul.RoutesRefreshedEvent; importorg.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping; importorg.springframework.context.ApplicationEvent; importorg.springframework.context.ApplicationEventPublisher; importorg.springframework.context.ApplicationListener; importorg.springframework.context.event.ContextRefreshedEvent; importorg.springframework.stereotype.Service; /** *路由刷新事件发布,与事件监听者 * *@authorxianliru@100tal.com *@version1.0 *@createDate2019/10/3015:27 */ @Service publicclassRefreshRouteServiceimplementsApplicationListener { @Autowired privateZuulHandlerMappingzuulHandlerMapping; privateHeartbeatMonitorheartbeatMonitor=newHeartbeatMonitor(); @Autowired ApplicationEventPublisherpublisher; @Autowired privateDiscoveryRouteLocatordynamicRouteLocator; /** *动态路由实现调用refreshRoute()发布刷新路由事件 */ publicvoidrefreshRoute(){ RoutesRefreshedEventroutesRefreshedEvent=newRoutesRefreshedEvent(dynamicRouteLocator); publisher.publishEvent(routesRefreshedEvent); } /** *事件监听者。监控检测事件刷新 *@paramevent */ @Override publicvoidonApplicationEvent(ApplicationEventevent){ if(eventinstanceofContextRefreshedEvent||eventinstanceofRefreshScopeRefreshedEvent||eventinstanceofRoutesRefreshedEvent){ //主动手动刷新。上下文刷新,配置属性刷新 zuulHandlerMapping.setDirty(true); }elseif(eventinstanceofHeartbeatEvent){ //心跳触发,将本地映射关系。关联到远程服务上 HeartbeatEventheartbeatEvent=(HeartbeatEvent)event; if(heartbeatMonitor.update(heartbeatEvent.getValue())){ zuulHandlerMapping.setDirty(true); } } } }
对外提供触发接口
packagecom.xian.cloud.controller; importcom.xian.cloud.event.RefreshRouteService; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.web.bind.annotation.GetMapping; importorg.springframework.web.bind.annotation.RestController; /** *手动刷新对外接口 * *@authorxianliru@100tal.com *@version1.0 *@createDate2019/10/3020:23 */ @RestController publicclassRefreshController{ @Autowired privateRefreshRouteServicerefreshRouteService; @GetMapping("/refresh") publicStringrefresh(){ refreshRouteService.refreshRoute(); return"refresh"; } }
数据库表结构
CREATETABLE`sys_zuul_route`( `id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'routerId', `path`varchar(255)NOTNULLCOMMENT'路由路径', `service_id`varchar(255)NOTNULLCOMMENT'服务名称', `url`varchar(255)DEFAULTNULLCOMMENT'url代理', `strip_prefix`char(1)DEFAULT'1'COMMENT'转发去掉前缀', `retryable`char(1)DEFAULT'1'COMMENT'是否重试', `enabled`char(1)DEFAULT'1'COMMENT'是否启用', `sensitiveHeaders_list`varchar(255)DEFAULTNULLCOMMENT'敏感请求头', `create_time`timestampNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间', `update_time`timestampNULLDEFAULTNULLONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间', `del_flag`char(1)DEFAULT'0'COMMENT'删除标识(0-正常,1-删除)', PRIMARYKEY(`id`) )ENGINE=InnoDBAUTO_INCREMENT=9DEFAULTCHARSET=utf8mb4ROW_FORMAT=DYNAMICCOMMENT='动态路由配置表'
将配置文件client消费者服务路由配置注释掉。设置数据源。从数据库中读取
启动服务打印日志
2019-10-3020:49:39.946 INFO63449---[TaskScheduler-1]c.xian.cloud.router.DynamicRouteLocator :添加数据库自定义的路由配置,path:/client/**,serviceId:cloud-discovery-client
2019-10-3020:49:40.397 INFO63449---[TaskScheduler-1]c.xian.cloud.router.DynamicRouteLocator :添加数据库自定义的路由配置,path:/client/**,serviceId:cloud-discovery-client
postman请求client接口看看是否能转发成功
基于zuul动态网关路由完成。
总结
以上所述是小编给大家介绍的SpringCloud网关服务zuul 动态路由的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。