From 72904de35cce85b74d516aff66e76c1b5fd14c0f Mon Sep 17 00:00:00 2001 From: smallchill Date: Sat, 18 May 2019 10:06:28 +0800 Subject: [PATCH] =?UTF-8?q?:tada:=20=E5=AE=89=E6=8E=92=E5=9F=BA=E4=BA=8Ena?= =?UTF-8?q?cos=E7=9A=84=E5=8A=A8=E6=80=81=E7=BD=91=E5=85=B3=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/dynamic/model/GatewayFilter.java | 41 +++++++ .../dynamic/model/GatewayPredicate.java | 41 +++++++ .../gateway/dynamic/model/GatewayRoute.java | 57 ++++++++++ .../dynamic/service/DynamicRouteService.java | 101 ++++++++++++++++++ .../service/DynamicRouteServiceListener.java | 85 +++++++++++++++ .../DiscoveryEndpoint.java} | 4 +- .../gateway/endpoint/RouteEndpoint.java | 86 +++++++++++++++ doc/nacos/routes/README.md | 1 + doc/nacos/routes/blade-gateway-dev.json | 28 +++++ 9 files changed, 442 insertions(+), 2 deletions(-) create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayFilter.java create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayPredicate.java create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayRoute.java create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteService.java create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteServiceListener.java rename blade-gateway/src/main/java/org/springblade/gateway/{controller/DiscoveryClientController.java => endpoint/DiscoveryEndpoint.java} (95%) create mode 100644 blade-gateway/src/main/java/org/springblade/gateway/endpoint/RouteEndpoint.java create mode 100644 doc/nacos/routes/README.md create mode 100644 doc/nacos/routes/blade-gateway-dev.json diff --git a/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayFilter.java b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayFilter.java new file mode 100644 index 00000000..b224c683 --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayFilter.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.dynamic.model; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 过滤器定义模型 + * + * @author Chill + */ +@Data +public class GatewayFilter { + + /** + * 过滤器对应的Name + */ + private String name; + + /** + * 对应的路由规则 + */ + private Map args = new LinkedHashMap<>(); +} diff --git a/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayPredicate.java b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayPredicate.java new file mode 100644 index 00000000..0c53a293 --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayPredicate.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.dynamic.model; + +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 路由断言定义模型 + * + * @author Chill + */ +@Data +public class GatewayPredicate { + + /** + * 断言对应的Name + */ + private String name; + + /** + * 配置的断言规则 + */ + private Map args = new LinkedHashMap<>(); +} diff --git a/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayRoute.java b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayRoute.java new file mode 100644 index 00000000..a9b6ff61 --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayRoute.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.dynamic.model; + + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * Gateway的路由定义模型 + * + * @author Chill + */ +@Data +public class GatewayRoute { + + /** + * 路由的id + */ + private String id; + + /** + * 路由断言集合配置 + */ + private List predicates = new ArrayList<>(); + + /** + * 路由过滤器集合配置 + */ + private List filters = new ArrayList<>(); + + /** + * 路由规则转发的目标uri + */ + private String uri; + + /** + * 路由执行的顺序 + */ + private int order = 0; +} diff --git a/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteService.java b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteService.java new file mode 100644 index 00000000..363ada95 --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteService.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.dynamic.service; + +import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionWriter; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 动态路由业务类 + * + * @author Chill + */ +@Service +public class DynamicRouteService implements ApplicationEventPublisherAware { + + private final RouteDefinitionWriter routeDefinitionWriter; + + private ApplicationEventPublisher publisher; + + public DynamicRouteService(RouteDefinitionWriter routeDefinitionWriter) { + this.routeDefinitionWriter = routeDefinitionWriter; + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } + + /** + * 增加路由 + */ + public String save(RouteDefinition definition) { + try { + routeDefinitionWriter.save(Mono.just(definition)).subscribe(); + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "save success"; + } catch (Exception e) { + e.printStackTrace(); + return "save failure"; + } + } + + /** + * 更新路由 + */ + public String update(RouteDefinition definition) { + try { + this.routeDefinitionWriter.delete(Mono.just(definition.getId())); + this.routeDefinitionWriter.save(Mono.just(definition)).subscribe(); + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "update success"; + } catch (Exception e) { + e.printStackTrace(); + return "update failure"; + } + } + + /** + * 更新路由 + */ + public String updateList(List routeDefinitions) { + routeDefinitions.forEach(this::update); + return "update done"; + } + + /** + * 删除路由 + */ + public String delete(String id) { + try { + this.routeDefinitionWriter.delete(Mono.just(id)); + return "delete success"; + } catch (Exception e) { + e.printStackTrace(); + return "delete failure"; + } + } + + +} diff --git a/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteServiceListener.java b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteServiceListener.java new file mode 100644 index 00000000..12bb00cc --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteServiceListener.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.dynamic.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; +import org.springblade.core.launch.constant.NacosConstant; +import org.springblade.core.launch.props.BladeProperties; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * 动态路由监听器 + * + * @author Chill + */ +@Order +@Component +public class DynamicRouteServiceListener { + + private final DynamicRouteService dynamicRouteService; + private final NacosDiscoveryProperties nacosDiscoveryProperties; + private final NacosConfigProperties nacosConfigProperties; + private final BladeProperties bladeProperties; + + public DynamicRouteServiceListener(DynamicRouteService dynamicRouteService, NacosDiscoveryProperties nacosDiscoveryProperties, NacosConfigProperties nacosConfigProperties, BladeProperties bladeProperties) { + this.dynamicRouteService = dynamicRouteService; + this.nacosDiscoveryProperties = nacosDiscoveryProperties; + this.nacosConfigProperties = nacosConfigProperties; + this.bladeProperties = bladeProperties; + dynamicRouteServiceListener(); + } + + /** + * 监听Nacos下发的动态路由配置 + */ + private void dynamicRouteServiceListener() { + try { + String dataId = NacosConstant.dataId(bladeProperties.getName(), bladeProperties.getEnv(), NacosConstant.NACOS_CONFIG_JSON_FORMAT); + String group = nacosConfigProperties.getGroup(); + String serverAddr = nacosDiscoveryProperties.getServerAddr(); + ConfigService configService = NacosFactory.createConfigService(serverAddr); + String content = configService.getConfig(dataId, group, 5000); + System.out.println(content); + configService.addListener(dataId, group, new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + List routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class); + dynamicRouteService.updateList(routeDefinitions); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + } catch (NacosException ignored) { + + } + } + +} diff --git a/blade-gateway/src/main/java/org/springblade/gateway/controller/DiscoveryClientController.java b/blade-gateway/src/main/java/org/springblade/gateway/endpoint/DiscoveryEndpoint.java similarity index 95% rename from blade-gateway/src/main/java/org/springblade/gateway/controller/DiscoveryClientController.java rename to blade-gateway/src/main/java/org/springblade/gateway/endpoint/DiscoveryEndpoint.java index 20409ec3..9b9393f5 100644 --- a/blade-gateway/src/main/java/org/springblade/gateway/controller/DiscoveryClientController.java +++ b/blade-gateway/src/main/java/org/springblade/gateway/endpoint/DiscoveryEndpoint.java @@ -14,7 +14,7 @@ * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ -package org.springblade.gateway.controller; +package org.springblade.gateway.endpoint; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,7 +37,7 @@ import java.util.Map; @RestController @AllArgsConstructor @RequestMapping("/discovery") -public class DiscoveryClientController { +public class DiscoveryEndpoint { private final DiscoveryClient discoveryClient; diff --git a/blade-gateway/src/main/java/org/springblade/gateway/endpoint/RouteEndpoint.java b/blade-gateway/src/main/java/org/springblade/gateway/endpoint/RouteEndpoint.java new file mode 100644 index 00000000..4b49902b --- /dev/null +++ b/blade-gateway/src/main/java/org/springblade/gateway/endpoint/RouteEndpoint.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the dreamlu.net developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: Chill 庄骞 (smallchill@163.com) + */ +package org.springblade.gateway.endpoint; + +import lombok.AllArgsConstructor; +import org.springblade.gateway.dynamic.model.GatewayPredicate; +import org.springblade.gateway.dynamic.model.GatewayRoute; +import org.springblade.gateway.dynamic.service.DynamicRouteService; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionLocator; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Flux; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +/** + * 动态路由端点 + * + * @author Chill + */ +@RestController +@AllArgsConstructor +@RequestMapping("/route") +public class RouteEndpoint { + + private DynamicRouteService dynamicRouteService; + private RouteDefinitionLocator routeDefinitionLocator; + + @GetMapping("/list") + public Flux list() { + return routeDefinitionLocator.getRouteDefinitions(); + } + + @PostMapping("/save") + public String save(@RequestBody GatewayRoute gatewayRoute) { + RouteDefinition definition = assembleRouteDefinition(gatewayRoute); + return this.dynamicRouteService.save(definition); + } + + @PostMapping("/update") + public String update(@RequestBody GatewayRoute gatewayRoute) { + RouteDefinition definition = assembleRouteDefinition(gatewayRoute); + return this.dynamicRouteService.update(definition); + } + + @GetMapping("/delete/{id}") + public String delete(@PathVariable String id) { + return this.dynamicRouteService.delete(id); + } + + private RouteDefinition assembleRouteDefinition(GatewayRoute gatewayRoute) { + RouteDefinition definition = new RouteDefinition(); + List pdList = new ArrayList<>(); + definition.setId(gatewayRoute.getId()); + List gatewayPredicateDefinitionList = gatewayRoute.getPredicates(); + for (GatewayPredicate gpDefinition : gatewayPredicateDefinitionList) { + PredicateDefinition predicate = new PredicateDefinition(); + predicate.setArgs(gpDefinition.getArgs()); + predicate.setName(gpDefinition.getName()); + pdList.add(predicate); + } + definition.setPredicates(pdList); + URI uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri(); + definition.setUri(uri); + return definition; + } + +} diff --git a/doc/nacos/routes/README.md b/doc/nacos/routes/README.md new file mode 100644 index 00000000..7583e153 --- /dev/null +++ b/doc/nacos/routes/README.md @@ -0,0 +1 @@ +动态网关配置 \ No newline at end of file diff --git a/doc/nacos/routes/blade-gateway-dev.json b/doc/nacos/routes/blade-gateway-dev.json new file mode 100644 index 00000000..1fef883e --- /dev/null +++ b/doc/nacos/routes/blade-gateway-dev.json @@ -0,0 +1,28 @@ +[ + { + "id": "desk-route", + "order": 0, + "predicates": [ + { + "name": "Path", + "args": { + "pattern": "/blade-desk/**" + } + } + ], + "filters": [], + "uri": "lb://blade-desk-me" + }, + { + "id": "example-route", + "order": 0, + "predicates": [{ + "name": "Path", + "args": { + "pattern": "/example" + } + }], + "filters": [], + "uri": "http://www.example.com" + } +]