From eed300274c7fcf524f3ec7b5904fd3a7d46a94a9 Mon Sep 17 00:00:00 2001 From: qyx <565485304@qq.com> Date: Fri, 2 Aug 2024 17:35:29 +0800 Subject: [PATCH] feat(master): SpringCLoud Predicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Predicate 相关的逻辑代码更新 --- .../README-SpringCloud-Gateway.md | 41 ++++++ .../README.md | 3 - .../dev-protocol-springcloud-gateway/pom.xml | 72 ++++++++++ .../java/org/example/GatewayApplication.java | 17 +++ .../src/main/java/org/example/Main.java | 7 - .../example/conf/DynamicRouteServiceImpl.java | 122 +++++++++++++++++ .../conf/DynamicRouteServiceImplByNacos.java | 127 ++++++++++++++++++ .../java/org/example/conf/GatewayConfig.java | 46 +++++++ .../src/main/resources/bootstrap.yml | 54 ++++++++ .../src/main/resources/http/login.http | 17 +++ .../src/main/resources/http/nacos-client.http | 5 + .../org/example/GatewayApplicationTest.java | 18 +++ .../org/example/service/PredicateTest.java | 83 ++++++++++++ .../dev-protocol-springcloud-nacos/pom.xml | 15 ++- .../controller/NacosClientController.java | 51 +++++++ .../{application.yml => bootstrap.yml} | 20 +-- .../src/main/resources/http/nacos-client.http | 6 +- 17 files changed, 676 insertions(+), 28 deletions(-) create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/README-SpringCloud-Gateway.md delete mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/README.md create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/GatewayApplication.java delete mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/Main.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImpl.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImplByNacos.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/GatewayConfig.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/bootstrap.yml create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/login.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/nacos-client.http create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/GatewayApplicationTest.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/service/PredicateTest.java create mode 100644 dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/java/org/example/controller/NacosClientController.java rename dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/{application.yml => bootstrap.yml} (86%) diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README-SpringCloud-Gateway.md b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README-SpringCloud-Gateway.md new file mode 100644 index 0000000..340135d --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README-SpringCloud-Gateway.md @@ -0,0 +1,41 @@ +# SpringCloud - Gateway + + +## 1. 基础介绍 + +- SpringCloud Gateway 的核心概念 + - SpringCloud Gateway 是 Spring 官方最新推出的一款基于 SpringFramework 5, Project Reactor 和SpringBoot 2之上开发的网关 + - 它与第一代网关 Zuu 不同的是: gateway 是异步非阻塞的(netty + webflux 实现), zuul是同步阻塞请求的 + - Gateway 三大组成部分 + - Route 路由(ID + 目标URL) - Predicate 断言 - Filter 过滤器 + + +- SpringCloud Gateway 的工作模型 + - SpringCloud Gateway 工作模型图示及解读 + - 请求发送到网关,经由分发器将请求匹配到相应的 HandlerMapping + - 请求和处理器之间有一个映射,路由到网关处理程序,即 Web Handler + - 执行特定的请求过滤器链 (Filters Proxy Filter) + - 最终到达代理的微服务 (Proxied Service) +--- +## 2. 谓词 Predicate 的原理与应用 + +- 参考: [PredicateTest.java] + +## 3. 集成 Nacos 实现动态路由配置 + +- 静态路由配置 + - 静态路由配置写在配置文件中(yml或者 properties 文件中),端点是:spring.cloud.gateway + - 缺点非常明显,每次改动都需要网关模块重新部署 +--- +## 4. 注册网关事件监听器 + +- 参考: [DynamicRouteServiceImpl.java] | [DynamicRouteServiceImplByNacos.java] + +- 验证网关监听器的可用性 修改看是否可以生效, 已经测试成功 + +--- +## 5. 解读 SpringCloud Gateway Filter + + + + diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README.md b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README.md deleted file mode 100644 index a2bff58..0000000 --- a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SpringCloud - Gateway - -- 对 SpringCloud - Gateway 进行研究 diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/pom.xml b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/pom.xml index 12cfa97..c9360ad 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/pom.xml +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/pom.xml @@ -11,6 +11,8 @@ dev-protocol-springcloud-gateway + 1.0-SNAPSHOT + jar 8 @@ -18,4 +20,74 @@ UTF-8 + + e-commerce-gateway + Spring Cloud Gateway + + + + + + + + + org.springframework.boot + spring-boot-starter-test + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + org.springframework.cloud + spring-cloud-starter-gateway + + + org.projectlombok + lombok + + + + + + + + + + + + + + + + + + com.alibaba + fastjson + 1.2.51 + + + + + + ${artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/GatewayApplication.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/GatewayApplication.java new file mode 100644 index 0000000..02c93e2 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/GatewayApplication.java @@ -0,0 +1,17 @@ +package org.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + *

网关启动入口

+ * */ +@EnableDiscoveryClient +@SpringBootApplication +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } +} \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/Main.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/Main.java deleted file mode 100644 index 407f157..0000000 --- a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.example; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImpl.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImpl.java new file mode 100644 index 0000000..6768246 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImpl.java @@ -0,0 +1,122 @@ +package org.example.conf; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionLocator; +import org.springframework.cloud.gateway.route.RouteDefinitionWriter; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * 事件推送 Aware: 动态更新路由网关 Service + * + * 实现 ApplicationEventPublisherAware 事件推送接口 + * */ +@Slf4j +@Service +@SuppressWarnings("all") +public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware { + + /** 写路由定义 */ + private final RouteDefinitionWriter routeDefinitionWriter; + /** 获取路由定义 */ + private final RouteDefinitionLocator routeDefinitionLocator; + + /** 事件发布 */ + private ApplicationEventPublisher publisher; + + public DynamicRouteServiceImpl(RouteDefinitionWriter routeDefinitionWriter, + RouteDefinitionLocator routeDefinitionLocator) { + this.routeDefinitionWriter = routeDefinitionWriter; + this.routeDefinitionLocator = routeDefinitionLocator; + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + // 完成事件推送句柄的初始化 + this.publisher = applicationEventPublisher; + } + + /** + *

增加路由定义

+ * */ + public String addRouteDefinition(RouteDefinition definition) { + + log.info("gateway add route: [{}]", definition); + + // 保存路由配置并发布 + routeDefinitionWriter.save(Mono.just(definition)).subscribe(); + // 发布事件通知给 Gateway, 同步新增的路由定义 + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + + return "success"; + } + + /** + *

更新路由

+ * */ + public String updateList(List definitions) { + + log.info("gateway update route: [{}]", definitions); + + // 先拿到当前 Gateway 中存储的路由定义 + List routeDefinitionsExits = + routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst(); + if (!CollectionUtils.isEmpty(routeDefinitionsExits)) { + // 清除掉之前所有的 "旧的" 路由定义 + routeDefinitionsExits.forEach(rd -> { + log.info("delete route definition: [{}]", rd); + deleteById(rd.getId()); + }); + } + + // 把更新的路由定义同步到 gateway 中 + definitions.forEach(definition -> updateByRouteDefinition(definition)); + return "success"; + } + + /** + *

根据路由 id 删除路由配置

+ * */ + private String deleteById(String id) { + + try { + log.info("gateway delete route id: [{}]", id); + this.routeDefinitionWriter.delete(Mono.just(id)).subscribe(); + // 发布事件通知给 gateway 更新路由定义 + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "delete success"; + } catch (Exception ex) { + log.error("gateway delete route fail: [{}]", ex.getMessage(), ex); + return "delete fail"; + } + } + + /** + *

更新路由

+ * 更新的实现策略比较简单: 删除 + 新增 = 更新 + * */ + private String updateByRouteDefinition(RouteDefinition definition) { + + try { + log.info("gateway update route: [{}]", definition); + this.routeDefinitionWriter.delete(Mono.just(definition.getId())); + } catch (Exception ex) { + return "update fail, not find route routeId: " + definition.getId(); + } + + try { + this.routeDefinitionWriter.save(Mono.just(definition)).subscribe(); + this.publisher.publishEvent(new RefreshRoutesEvent(this)); + return "success"; + } catch (Exception ex) { + return "update route fail"; + } + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImplByNacos.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImplByNacos.java new file mode 100644 index 0000000..0f891e7 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/DynamicRouteServiceImplByNacos.java @@ -0,0 +1,127 @@ +package org.example.conf; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.common.utils.CollectionUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.concurrent.Executor; +import java.util.List; +import java.util.Properties; + +/** + *

通过 nacos 下发动态路由配置, 监听 Nacos 中路由配置变更

+ * */ +@Slf4j +@Component +@DependsOn({"gatewayConfig"}) // 依赖于 GatewayConfig 这个 Bean , 注意要首字母小写 +public class DynamicRouteServiceImplByNacos { + /** Nacos 配置服务 */ + private ConfigService configService; + private final DynamicRouteServiceImpl dynamicRouteService; + + public DynamicRouteServiceImplByNacos(DynamicRouteServiceImpl dynamicRouteService) { + this.dynamicRouteService = dynamicRouteService; + } + + /** + *

Bean 在容器中构造完成之后会执行 init 方法

+ * */ + @PostConstruct + public void init() { + + log.info("gateway route init...."); + + try { + // 初始化 Nacos 配置客户端 + configService = initConfigService(); + if (null == configService) { + log.error("init config service fail"); + return; + } + + // 通过 Nacos Config 并指定路由配置路径去获取路由配置 + String configInfo = configService.getConfig( + GatewayConfig.NACOS_ROUTE_DATA_ID, + GatewayConfig.NACOS_ROUTE_GROUP, + GatewayConfig.DEFAULT_TIMEOUT + ); + + log.info("get current gateway config: [{}]", configInfo); + List definitionList = JSON.parseArray(configInfo, RouteDefinition.class); + + if (CollectionUtils.isNotEmpty(definitionList)) { + for (RouteDefinition definition : definitionList) { + log.info("init gateway config: [{}]", definition.toString()); + dynamicRouteService.addRouteDefinition(definition); + } + } + + } catch (Exception ex) { + log.error("gateway route init has some error: [{}]", ex.getMessage(), ex); + } + + // 设置监听器 + dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP); + } + + /** + *

初始化 Nacos Config

+ * */ + private ConfigService initConfigService() { + + try { + Properties properties = new Properties(); + properties.setProperty("serverAddr", GatewayConfig.NACOS_SERVER_ADDR); + properties.setProperty("namespace", GatewayConfig.NACOS_NAMESPACE); + return configService = NacosFactory.createConfigService(properties); + } catch (Exception ex) { + log.error("init gateway nacos config error: [{}]", ex.getMessage(), ex); + return null; + } + } + + /** + *

监听 Nacos 下发的动态路由配置

+ * */ + private void dynamicRouteByNacosListener(String dataId, String group) { + + try { + // 给 Nacos Config 客户端增加一个监听器 + configService.addListener(dataId, group, new Listener() { + + /** + *

自己提供线程池执行操作

+ * */ + @Override + public Executor getExecutor() { + // 通常不需要自己提供用默认提供的即可 + return null; + } + + /** + *

监听器收到配置更新

+ * @param configInfo Nacos 中最新的配置定义 + * */ + @Override + public void receiveConfigInfo(String configInfo) { + + log.info("start to update config: [{}]", configInfo); + List definitionList = JSON.parseArray(configInfo, RouteDefinition.class); + log.info("update route: [{}]", definitionList.toString()); + dynamicRouteService.updateList(definitionList); + } + }); + } catch (NacosException ex) { + log.error("dynamic update gateway config error: [{}]", ex.getMessage(), ex); + } + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/GatewayConfig.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/GatewayConfig.java new file mode 100644 index 0000000..0f347f6 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/java/org/example/conf/GatewayConfig.java @@ -0,0 +1,46 @@ +package org.example.conf; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + *

配置类, 读取 Nacos 相关的配置项, 用于配置监听器

+ * */ +@Configuration +public class GatewayConfig { + + /** 读取配置的超时时间 */ + public static final long DEFAULT_TIMEOUT = 30000; + + /** Nacos 服务器地址 */ + public static String NACOS_SERVER_ADDR; + + /** 命名空间 */ + public static String NACOS_NAMESPACE; + + /** data-id */ + public static String NACOS_ROUTE_DATA_ID; + + /** 分组 id */ + public static String NACOS_ROUTE_GROUP; + + @Value("${spring.cloud.nacos.discovery.server-addr}") + public void setNacosServerAddr(String nacosServerAddr) { + NACOS_SERVER_ADDR = nacosServerAddr; + } + + @Value("${spring.cloud.nacos.discovery.namespace}") + public void setNacosNamespace(String nacosNamespace) { + NACOS_NAMESPACE = nacosNamespace; + } + + @Value("${nacos.gateway.route.config.data-id}") + public void setNacosRouteDataId(String nacosRouteDataId) { + NACOS_ROUTE_DATA_ID = nacosRouteDataId; + } + + @Value("${nacos.gateway.route.config.group}") + public void setNacosRouteGroup(String nacosRouteGroup) { + NACOS_ROUTE_GROUP = nacosRouteGroup; + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/bootstrap.yml b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..fe928cb --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,54 @@ +server: + port: 9001 + servlet: + context-path: /dev-protocol-springcloud-gateway + +spring: + application: + name: dev-protocol-springcloud-gateway + cloud: + nacos: + discovery: + enabled: true # 如果不想使用 Nacos 进行服务注册和发现, 设置为 false 即可 + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + namespace: 1ccc74ae-9398-4dbe-b9d7-4f9addf9f40c + metadata: + management: + context-path: ${server.servlet.context-path}/actuator + # 静态路由 + # gateway: + # routes: + # - id: path_route # 路由的ID + # uri: 127.0.0.1:8080/user/{id} # 匹配后路由地址 + # predicates: # 断言, 路径相匹配的进行路由 + # - Path=/user/{id} +# kafka: +# bootstrap-servers: 127.0.0.1:9092 +# producer: +# retries: 3 +# consumer: +# auto-offset-reset: latest +# zipkin: +# sender: +# type: kafka # 默认是 web +# base-url: http://localhost:9411/ + main: + allow-bean-definition-overriding: true # 因为将来会引入很多依赖, 难免有重名的 bean + +# 这个地方独立配置, 是网关的数据, 代码 GatewayConfig.java 中读取被监听 +nacos: + gateway: + route: + config: + data-id: dev-protocol-springcloud-gateway-router + group: dev-protocol + +# 暴露端点 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: always diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/login.http b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/login.http new file mode 100644 index 0000000..25e22f1 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/login.http @@ -0,0 +1,17 @@ +### 登录 +POST 127.0.0.1:9001/imooc/e-commerce/login +Content-Type: application/json + +{ + "username": "Qinyi@imooc.com", + "password": "25d55ad283aa400af464c76d713c07ad" +} + +### +POST 127.0.0.1:9001/imooc/e-commerce/register +Content-Type: application/json + +{ + "username": "ImoocQinyi@imooc.com", + "password": "25d55ad283aa400af464c76d713c07ad" +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/nacos-client.http b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/nacos-client.http new file mode 100644 index 0000000..a0a713c --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/main/resources/http/nacos-client.http @@ -0,0 +1,5 @@ +### 查询服务 +GET http://127.0.0.1:9001/imooc/ecommerce-nacos-client/nacos-client/service-instance?serviceId=e-commerce-gateway +Accept: application/json +e-commerce-user: eyJhbGciOiJSUzI1NiJ9.eyJlLWNvbW1lcmNlLXVzZXIiOiJ7XCJpZFwiOjE3LFwidXNlcm5hbWVcIjpcIkltb29jUWlueWlAaW1vb2MuY29tXCJ9IiwianRpIjoiMGIxNzQyYWItMWU3OC00OTZjLWIyNTAtMjNkZGQ1ZGEyZTU1IiwiZXhwIjoxNjI0MjA0ODAwfQ.QKGHzohSHdYDHzUVHpe9gNPUgzfkPwrSbB-WiMWYjLlt2tr9BufzZM8bSt-whb_bd0hKoC6rkYYO0WUVR67uSML-2yaTL1xMIn8GH9Flyig3rpO4vefL3Hp2TXIpwHHa7WlKsLzcUpNk9lxWs2B5k0ICdYCH_jD5Tx6N7CzfSUG9u4fOnVeM9UFE2nX_DURupUh_DKCc2oOoMeyCSR7Ma8-Ab4WQU3r-U0YivR8G1A0kmKOIoTeRhM3LcPuxUPh3rCbrjzMg--fexRGw0O38Qsby6pz-ku2IlTyFXY6_jNOG1BZR34-jBOnaIciP1TExw9bFumeuC2GcowTHJVH1Nw +token: imooc diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/GatewayApplicationTest.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/GatewayApplicationTest.java new file mode 100644 index 0000000..5ed8a8e --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/GatewayApplicationTest.java @@ -0,0 +1,18 @@ +package org.example; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +/** + *

验证工程搭建的正确性测试用例

+ * */ +@SpringBootTest +@RunWith(SpringRunner.class) +public class GatewayApplicationTest { + + @Test + public void contextLoad() { + + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/service/PredicateTest.java b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/service/PredicateTest.java new file mode 100644 index 0000000..f53b38f --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-gateway/src/test/java/org/example/service/PredicateTest.java @@ -0,0 +1,83 @@ +package org.example.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +/** + *

Java8 Predicate 使用方法与思想

+ * */ +@Slf4j +@SpringBootTest +@RunWith(SpringRunner.class) +public class PredicateTest { + + public static List MICRO_SERVICE = Arrays.asList( + "nacos", "authority", "gateway", "ribbon", "feign", "hystrix", "e-commerce" + ); + + /** + *

test 方法主要用于参数符不符合规则, 返回值是 boolean

+ * */ + @Test + public void testPredicateTest() { + + Predicate letterLengthLimit = s -> s.length() > 5; + MICRO_SERVICE.stream().filter(letterLengthLimit).forEach(System.out::println); + } + + /** + *

and 方法等同于我们的逻辑与 &&, 存在短路特性, 需要所有的条件都满足

+ * */ + @Test + public void testPredicateAnd() { + + Predicate letterLengthLimit = s -> s.length() > 5; + Predicate letterStartWith = s -> s.startsWith("gate"); + + MICRO_SERVICE.stream().filter( + letterLengthLimit.and(letterStartWith) + ).forEach(System.out::println); + } + + /** + *

or 等同于我们的逻辑或 ||, 多个条件主要一个满足即可

+ * */ + @Test + public void testPredicateOr() { + + Predicate letterLengthLimit = s -> s.length() > 5; + Predicate letterStartWith = s -> s.startsWith("gate"); + + MICRO_SERVICE.stream().filter( + letterLengthLimit.or(letterStartWith) + ).forEach(System.out::println); + } + + /** + *

negate 等同于我们的逻辑非 !

+ * */ + @Test + public void testPredicateNegate() { + + Predicate letterStartWith = s -> s.startsWith("gate"); + MICRO_SERVICE.stream().filter(letterStartWith.negate()).forEach(System.out::println); + } + + /** + *

isEqual 类似于 equals(), 区别在于: 先判断对象是否为 NULL, + * 不为 NULL 再使用 equals 进行比较

+ * */ + @Test + public void testPredicateIsEqual() { + + Predicate equalGateway = s -> Predicate.isEqual("gateway").test(s); + MICRO_SERVICE.stream().filter(equalGateway).forEach(System.out::println); + } +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/pom.xml b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/pom.xml index 6d17103..234fece 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/pom.xml +++ b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/pom.xml @@ -25,11 +25,19 @@ + + + org.springframework.boot + spring-boot-starter-web + com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery - 2.2.3.RELEASE + + + org.projectlombok + lombok - - org.projectlombok - lombok - + diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/java/org/example/controller/NacosClientController.java b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/java/org/example/controller/NacosClientController.java new file mode 100644 index 0000000..ef1ad95 --- /dev/null +++ b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/java/org/example/controller/NacosClientController.java @@ -0,0 +1,51 @@ +package org.example.controller; + +import lombok.extern.slf4j.Slf4j; +import org.example.service.NacosClientService; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + *

nacos client controller

+ * */ +@Slf4j +@RestController +@RequestMapping("/nacos-client") +public class NacosClientController { + + private final NacosClientService nacosClientService; +// private final ProjectConfig projectConfig; + + + public NacosClientController(NacosClientService nacosClientService +// ProjectConfig projectConfig + ) { + this.nacosClientService = nacosClientService; +// this.projectConfig = projectConfig; + } + + + /** + *

根据 service id 获取服务所有的实例信息

+ * */ + @GetMapping("/service-instance") + public List logNacosClientInfo( + @RequestParam(defaultValue = "dev-protocol-spring-cloud-nacos") String serviceId) { + + log.info("coming in log nacos client info: [{}]", serviceId); + return nacosClientService.getNacosClientInfo(serviceId); + } + +/* *//** + *

动态获取 Nacos 中的配置信息

+ * *//* + @GetMapping("/project-config") + public ProjectConfig getProjectConfig() { + return projectConfig; + }*/ +} diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/application.yml b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/bootstrap.yml similarity index 86% rename from dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/application.yml rename to dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/bootstrap.yml index f4eed9c..50d513c 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/application.yml +++ b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/bootstrap.yml @@ -1,11 +1,11 @@ server: port: 8000 servlet: - context-path: /e-commerce-nacos-client + context-path: /dev-protocol-spring-cloud-nacos spring: application: - name: e-commerce-nacos-client # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时) + name: dev-protocol-spring-cloud-nacos # 应用名称也是构成 Nacos 配置管理 dataId 字段的一部分 (当 config.prefix 为空时) cloud: nacos: # 服务注册发现 @@ -64,11 +64,11 @@ spring: # enabled: true # 暴露端点 -#management: -# endpoints: -# web: -# exposure: -# include: '*' -# endpoint: -# health: -# show-details: always +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: always diff --git a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/http/nacos-client.http b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/http/nacos-client.http index 9a454e9..52b3860 100644 --- a/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/http/nacos-client.http +++ b/dev-protocol-springcloud/dev-protocol-springcloud-nacos/src/main/resources/http/nacos-client.http @@ -1,13 +1,13 @@ ### 查询服务实例信息 -GET http://127.0.0.1:8000/ecommerce-nacos-client/nacos-client/service-instance +GET http://127.0.0.1:8000/dev-protocol-spring-cloud-nacos/nacos-client/service-instance Accept: application/json ### 动态从 Nacos Server 中获取配置信息 -GET http://127.0.0.1:8000/ecommerce-nacos-client/nacos-client/project-config +GET http://127.0.0.1:8000/dev-protocol-spring-cloud-nacos/nacos-client/project-config Accept: application/json ### 查看 Sleuth 跟踪信息 -GET http://127.0.0.1:9001/imooc/ecommerce-nacos-client/sleuth/trace-info +GET http://127.0.0.1:9001/imooc/dev-protocol-spring-cloud-nacos/sleuth/trace-info Accept: application/json e-commerce-user: eyJhbGciOiJSUzI1NiJ9.eyJlLWNvbW1lcmNlLXVzZXIiOiJ7XCJpZFwiOjE3LFwidXNlcm5hbWVcIjpcIkltb29jUWlueWlAaW1vb2MuY29tXCJ9IiwianRpIjoiMGIxNzQyYWItMWU3OC00OTZjLWIyNTAtMjNkZGQ1ZGEyZTU1IiwiZXhwIjoxNjI0MjA0ODAwfQ.QKGHzohSHdYDHzUVHpe9gNPUgzfkPwrSbB-WiMWYjLlt2tr9BufzZM8bSt-whb_bd0hKoC6rkYYO0WUVR67uSML-2yaTL1xMIn8GH9Flyig3rpO4vefL3Hp2TXIpwHHa7WlKsLzcUpNk9lxWs2B5k0ICdYCH_jD5Tx6N7CzfSUG9u4fOnVeM9UFE2nX_DURupUh_DKCc2oOoMeyCSR7Ma8-Ab4WQU3r-U0YivR8G1A0kmKOIoTeRhM3LcPuxUPh3rCbrjzMg--fexRGw0O38Qsby6pz-ku2IlTyFXY6_jNOG1BZR34-jBOnaIciP1TExw9bFumeuC2GcowTHJVH1Nw token: imooc