diff --git a/README.md b/README.md index fffbe0517..3768ff02b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -一个涵盖五个主流技术栈的**正经**仓库: +> 友情提示:因为提供了 50000+ 行示例代码,所以艿艿默认注释了所有 Maven Module。 +> +> 胖友可以根据自己的需要,修改 [`pom.xml`](https://github.com/YunaiV/SpringBoot-Labs/blob/master/pom.xml) 即可。 + +一个涵盖六个主流技术栈的**正经**仓库: * [《Spring Boot 专栏》](https://github.com/YunaiV/SpringBoot-Labs#spring-boot-%E4%B8%93%E6%A0%8F) * [《Spring Cloud Alibaba 专栏》](https://github.com/YunaiV/SpringBoot-Labs#spring-cloud-alibaba-%E4%B8%93%E6%A0%8F) * [《Spring Cloud 专栏》](https://github.com/YunaiV/SpringBoot-Labs#spring-cloud-%E4%B8%93%E6%A0%8F) @@ -35,7 +39,7 @@ * [《芋道 Spring Boot 热部署入门》](http://www.iocoder.cn/Spring-Boot/hot-swap/?github) 对应 [lab-48](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-48) * [《芋道 Spring Boot 消除冗余代码 Lombok 入门》](http://www.iocoder.cn/Spring-Boot/Lombok/?github) 对应 [lab-49](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-49) -* 《芋道 Spring Boot 对象转换 MapStruct 入门》计划中... +* [《芋道 Spring Boot 对象转换 MapStruct 入门》](http://www.iocoder.cn/Spring-Boot/MapStruct/?github) 对应 [lab-55](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-55) ## Web 开发 @@ -51,6 +55,7 @@ ## RPC 开发 * [《芋道 Spring Boot Dubbo 入门》](http://www.iocoder.cn/Spring-Boot/Dubbo/?github) 对应 [lab-30](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-30) +* [《芋道 Spring Boot 声明式调用 Feign 入门》](http://www.iocoder.cn/Spring-Boot/Feign/?github) 对应 [lab-58](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-58) * 《芋道 Spring Boot Motan 入门》计划中... * 《芋道 Spring Boot WebService 入门》计划中... * 《芋道 Spring Boot SOFARPC 入门》计划中... @@ -114,8 +119,8 @@ ## 服务容错 * [《芋道 Spring Boot 服务容错 Sentinel 入门》](http://www.iocoder.cn/Spring-Boot/Sentinel/?github) 对应 [lab-46](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-46) -* 《芋道 Spring Boot 服务容错 Hystrix 入门》计划中... -* 《芋道 Spring Boot 服务容错 Resilience4j 入门》计划中... +* [《芋道 Spring Boot 服务容错 Hystrix 入门》](http://www.iocoder.cn/Spring-Boot/Hystrix/?github) 对应 [lab-57](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-57) +* [《芋道 Spring Boot 服务容错 Resilience4j 入门》](http://www.iocoder.cn/Spring-Boot/Resilience4j/?github) 对应 [lab-59](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-59) ## 监控管理 @@ -162,7 +167,7 @@ ## 注册中心 * [《芋道 Spring Cloud Alibaba 注册中心 Nacos 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Nacos-Discovery/?github) 对应 [labx-01](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-01) -* 《芋道 Spring Cloud Netflix 注册中心 Eureka 入门》计划中... +* [《芋道 Spring Cloud Netflix 注册中心 Eureka 入门》](http://www.iocoder.cn/Spring-Cloud/Netflix-Eureka?github) 对应 [labx-22](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-22) * 《芋道 Spring Cloud 注册中心 Zookeeper 入门》计划中... * 《芋道 Spring Cloud 注册中心 Consul 入门》计划中... * 《芋道 Spring Cloud 注册中心 Etcd 入门》计划中... @@ -176,15 +181,22 @@ ## 服务容错 * [《芋道 Spring Cloud Alibaba 服务容错 Sentinel 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Sentinel/?github) 对应 [labx-04](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-04) -* 《芋道 Spring Cloud Netflix 服务容错 Hystrix 入门》计划中... -* 《芋道 Spring Cloud 服务容错 Resilience4j 入门》计划中... +* [《芋道 Spring Cloud Netflix 服务容错 Hystrix 入门》](http://www.iocoder.cn/Spring-Cloud/Netflix-Hystrix/?github) 对应 [labx-23](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-23) +* [《芋道 Spring Cloud 服务容错 Resilience4j 入门》](http://www.iocoder.cn/Spring-Cloud/Resilience4j/?github) 对应 [lab-59](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-59) +* 《芋道 Spring Cloud 服务容错 Spring Cloud CircuitBreaker》计划中... ## API 网关 * [《芋道 Spring Cloud 服务网关 Spring Cloud Gateway 入门》](http://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Gateway/?github) 对应 [labx-08](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-08) -* 《芋道 Spring Cloud Netflix 服务网关 Zuul 入门》计划中... +* [《芋道 Spring Cloud Netflix 服务网关 Zuul 入门》](http://www.iocoder.cn/Spring-Cloud/Netflix-Zuul/?github) 对应 对应 [labx-21](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-21) * [《性能测试 —— Spring Cloud Gateway、Zuul 基准测试》](http://www.iocoder.cn/Performance-Testing/SpringCloudGateway-Zuul-benchmark/?github) 对应 [lab-07](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-07) +> 如下非 Spring Cloud 网关,先放在这里... + +* [《芋道 APISIX 极简入门(国产微服务网关)》](http://www.iocoder.cn/APISIX/install/?github) 对应 [lab-56](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-56) +* [《芋道 Soul 极简入门(国产微服务网关)》](http://www.iocoder.cn/Soul/install/?github) 对应 [lab-60](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-60) +* [《芋道 Kong 极简入门(微服务网关)》](http://www.iocoder.cn/Kong/install/?github) 对应 [lab-56](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-56) + ## 配置中心 * [《芋道 Spring Cloud Alibaba 配置中心 Nacos 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Nacos-Config/?github) 对应 [labx-05](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-05) @@ -240,19 +252,35 @@ * [《芋道 Spring Boot Dubbo 入门》](http://www.iocoder.cn/Spring-Boot/Dubbo/?github)的[「2. XML 配置」](#)和[「3. 注解配置」](#)小节 **[Nacos](http://www.iocoder.cn/Nacos/install/?github)** +* [《芋道 Spring Boot Dubbo 入门》](http://www.iocoder.cn/Spring-Boot/Dubbo/?github)的[「6. 整合 Nacos」](#)小节 * [《芋道 Spring Cloud Alibaba 服务调用 Dubbo 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Dubbo/?github)的[「2. 快速入门」](#)小节 -## 服务保障 +## 服务容错 **[Sentinel](http://www.iocoder.cn/Sentinel/install/?github)** +* [《芋道 Spring Boot Dubbo 入门》](http://www.iocoder.cn/Spring-Boot/Dubbo/?github)的[「7. 整合 Sentinel」](#)小节 * [《芋道 Spring Cloud Alibaba 服务调用 Dubbo 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Dubbo/?github)的[「6. 整合 Sentinel」](#)小节 +**[Hystrix](http://www.iocoder.cn/categories/Hystrix/?github)** +* [《芋道 Spring Boot 服务容错 Hystrix 入门》](http://www.iocoder.cn/Spring-Boot/Hystrix/?github)的[「6. 集成到 Dubbo」](#)小节 +* [《芋道 Spring Cloud Netflix 服务容错 Hystrix 入门》](http://www.iocoder.cn/Spring-Cloud/Netflix-Hystrix/?github)的[「10. 集成到 Dubbo」](#)小节 + +**[Resilience4j](http://www.iocoder.cn/categories/Resilience4j/?github)** +* [《芋道 Spring Boot 服务容错 Resilience4j 入门》](http://www.iocoder.cn/Spring-Boot/Resilience4j/?github)的[「10. 集成到 Dubbo」](#)小节 + +## API 网关 + +* [《芋道 Soul 极简入门(国产微服务网关)》](http://www.iocoder.cn/Soul/install/?github)的[「3. 接入 Dubbo 应用」](#)小节 + ## 分布式事务 **[Seata](http://www.iocoder.cn/Seata/install/?github)** * [《芋道 Dubbo 分布式事务 Seata 入门》](http://www.iocoder.cn/Dubbo/Seata/?github) 对应 [lab-53](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-53) * [《芋道 Spring Cloud Alibaba 分布式事务 Seata 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Seata/?github)的[「2. AT 模式 + Dubbo」](#)小节 +**[TCC Transaction](http://www.iocoder.cn/categories/TCC-Transaction/?github)** +* [《TCC-Transaction 源码分析 —— Dubbo 支持》](http://www.iocoder.cn/TCC-Transaction/dubbo-support/?self) + ## 链路追踪 **[SkyWalking](http://www.iocoder.cn/SkyWalking/install/?github)** @@ -267,7 +295,7 @@ ## RocketMQ -* [《RocketMQ 安装部署》](http://www.iocoder.cn/RocketMQ/install/?github) +* [《RocketMQ 极简入门》](http://www.iocoder.cn/RocketMQ/install/?github) * [《芋道 Spring Boot 消息队列 RocketMQ 入门》](http://www.iocoder.cn/Spring-Boot/RocketMQ/?github) 对应 [lab-31](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-31) * [《芋道 Spring Cloud Alibaba 消息队列 RocketMQ 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/RocketMQ/?github) 对应 [labx-06](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-06) * [《芋道 Spring Cloud Alibaba 事件总线 Bus RocketMQ 入门》](http://www.iocoder.cn/Spring-Cloud-Alibaba/Bus-RocketMQ/?github) 对应 [labx-20](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-20) @@ -277,7 +305,7 @@ ## RabbitMQ -* [《RabbitMQ 安装部署》](http://www.iocoder.cn/RabbitMQ/install/?github) +* [《RabbitMQ 极简入门》](http://www.iocoder.cn/RabbitMQ/install/?github) * [《芋道 Spring Boot 消息队列 RabbitMQ 入门》](http://www.iocoder.cn/Spring-Boot/RabbitMQ/?github) 对应 [lab-04](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-04) * [《芋道 Spring Cloud 消息队列 RabbitMQ 入门》](http://www.iocoder.cn/Spring-Cloud/RabbitMQ/?github) 对应 [labx-10](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-10) * [《芋道 Spring Cloud 事件总线 Bus RabbitMQ 入门》](http://www.iocoder.cn/Spring-Cloud/Bus-RabbitMQ/?github) 对应 [labx-19](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-19) @@ -285,7 +313,7 @@ ## Kafka -* [《Kafka 安装部署》](http://www.iocoder.cn/Kafka/install/?github) +* [《Kafka 极简入门》](http://www.iocoder.cn/Kafka/install/?github) * [《芋道 Spring Boot 消息队列 Kafka 入门》](http://www.iocoder.cn/Spring-Boot/Kafka/?github) 对应 [lab-03](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-03) * [《芋道 Spring Cloud 消息队列 Kafka 入门》](http://www.iocoder.cn/Spring-Cloud/Kafka/?github) 对应 [labx-11](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-11) * [《芋道 Spring Cloud 事件总线 Bus Kafka 入门》](http://www.iocoder.cn/Spring-Cloud/Bus-Kafka/?github) 对应 [labx-18](https://github.com/YunaiV/SpringBoot-Labs/tree/master/labx-18) @@ -293,7 +321,7 @@ ## ActiveMQ -* [《ActiveMQ 安装部署》](http://www.iocoder.cn/ActiveMQ/install/?github) +* [《ActiveMQ 极简入门》](http://www.iocoder.cn/ActiveMQ/install/?github) * [《芋道 Spring Boot 消息队列 ActiveMQ 入门》](http://www.iocoder.cn/Spring-Boot/ActiveMQ/?github) 对应 [lab-32](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-32) * [《芋道 Spring Cloud 消息队列 ActiveMQ 入门》](http://www.iocoder.cn/Spring-Cloud/ActiveMQ/?github) diff --git a/lab-08/pom.xml b/lab-08/pom.xml index bd20c0f78..bc3bdcfb9 100644 --- a/lab-08/pom.xml +++ b/lab-08/pom.xml @@ -19,7 +19,7 @@ - + diff --git a/lab-30/lab-30-dubbo-annotations-nacos/pom.xml b/lab-30/lab-30-dubbo-annotations-nacos/pom.xml new file mode 100644 index 000000000..28352f707 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/pom.xml @@ -0,0 +1,21 @@ + + + + lab-30 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-30-dubbo-annotations-nacos + pom + + user-rpc-service-api-03 + user-rpc-service-provider-03 + user-rpc-service-consumer-03 + + + + diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/pom.xml b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/pom.xml new file mode 100644 index 000000000..addececb5 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/pom.xml @@ -0,0 +1,15 @@ + + + + lab-30-dubbo-annotations-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + user-rpc-service-api-03 + + + diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java new file mode 100644 index 000000000..d65cb1fdc --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java @@ -0,0 +1,18 @@ +package cn.iocoder.springboot.lab30.rpc.api; + +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; + +/** + * 用户服务 RPC Service 接口 + */ +public interface UserRpcService { + + /** + * 根据指定用户编号,获得用户信息 + * + * @param id 用户编号 + * @return 用户信息 + */ + UserDTO get(Integer id); + +} diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java new file mode 100644 index 000000000..806923fa0 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-api-03/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab30.rpc.dto; + +import java.io.Serializable; + +/** + * 用户信息 DTO + */ +public class UserDTO implements Serializable { + + /** + * 用户编号 + */ + private Integer id; + /** + * 昵称 + */ + private String name; + /** + * 性别 + */ + private Integer gender; + + public Integer getId() { + return id; + } + + public UserDTO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public UserDTO setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/pom.xml b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/pom.xml new file mode 100644 index 000000000..63d224685 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/pom.xml @@ -0,0 +1,67 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + 4.0.0 + + user-rpc-service-consumer-03 + + + + + cn.iocoder.springboot.labs + user-rpc-service-api-03 + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + + + + + + + + + + + + + com.alibaba.nacos + nacos-client + 1.2.1 + + + org.apache.dubbo + dubbo-registry-nacos + 2.7.4.1 + + + + + diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java new file mode 100644 index 000000000..1a744ca9b --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java @@ -0,0 +1,38 @@ +package cn.iocoder.springboot.lab30.rpc; + +import cn.iocoder.springboot.lab30.rpc.api.UserRpcService; +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; + +@SpringBootApplication +public class ConsumerApplication { + + public static void main(String[] args) { + // 启动 Spring Boot 应用 + ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); + } + + @Component + public class UserRpcServiceTest implements CommandLineRunner { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Reference(version = "${dubbo.consumer.UserRpcService.version}") + private UserRpcService userRpcService; + + @Override + public void run(String... args) throws Exception { + UserDTO user = userRpcService.get(1); + logger.info("[run][发起一次 Dubbo RPC 请求,获得用户为({})", user); + } + + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/resources/application.yaml b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/resources/application.yaml new file mode 100644 index 000000000..6042c876e --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-consumer-03/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service-consumer # 应用名 + # Dubbo 注册中心配置 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 消费者配置 + consumer: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/pom.xml b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/pom.xml new file mode 100644 index 000000000..29a22d182 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/pom.xml @@ -0,0 +1,67 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + 4.0.0 + + user-rpc-service-provider-03 + + + + + cn.iocoder.springboot.labs + user-rpc-service-api-03 + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + + + + + + + + + + + + + com.alibaba.nacos + nacos-client + 1.2.1 + + + org.apache.dubbo + dubbo-registry-nacos + 2.7.4.1 + + + + + diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java new file mode 100644 index 000000000..2ba636636 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java @@ -0,0 +1,14 @@ +package cn.iocoder.springboot.lab30.rpc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ProviderApplication { + + public static void main(String[] args) { + // 启动 Spring Boot 应用 + SpringApplication.run(ProviderApplication.class, args); + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java new file mode 100644 index 000000000..fe6ef676c --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab30.rpc.service; + +import cn.iocoder.springboot.lab30.rpc.api.UserRpcService; +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; +import org.apache.dubbo.config.annotation.Service; + +@Service(version = "${dubbo.provider.UserRpcService.version}") +public class UserRpcServiceImpl implements UserRpcService { + + @Override + public UserDTO get(Integer id) { + return new UserDTO().setId(id) + .setName("没有昵称:" + id) + .setGender(id % 2 + 1); // 1 - 男;2 - 女 + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/resources/application.yaml b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/resources/application.yaml new file mode 100644 index 000000000..0beae3f8b --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-nacos/user-rpc-service-provider-03/src/main/resources/application.yaml @@ -0,0 +1,20 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service-provider # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # Dubbo 服务提供者配置 + provider: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab30.rpc.service diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/pom.xml b/lab-30/lab-30-dubbo-annotations-sentinel/pom.xml new file mode 100644 index 000000000..13cf07bb3 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/pom.xml @@ -0,0 +1,21 @@ + + + + lab-30 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-30-dubbo-annotations-sentinel + pom + + user-rpc-service-api-04 + user-rpc-service-provider-04 + user-rpc-service-consumer-04 + + + + diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/pom.xml b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/pom.xml new file mode 100644 index 000000000..139ef66b5 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/pom.xml @@ -0,0 +1,15 @@ + + + + lab-30-dubbo-annotations-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + user-rpc-service-api-04 + + + diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java new file mode 100644 index 000000000..d65cb1fdc --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/api/UserRpcService.java @@ -0,0 +1,18 @@ +package cn.iocoder.springboot.lab30.rpc.api; + +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; + +/** + * 用户服务 RPC Service 接口 + */ +public interface UserRpcService { + + /** + * 根据指定用户编号,获得用户信息 + * + * @param id 用户编号 + * @return 用户信息 + */ + UserDTO get(Integer id); + +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java new file mode 100644 index 000000000..806923fa0 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-api-04/src/main/java/cn/iocoder/springboot/lab30/rpc/dto/UserDTO.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab30.rpc.dto; + +import java.io.Serializable; + +/** + * 用户信息 DTO + */ +public class UserDTO implements Serializable { + + /** + * 用户编号 + */ + private Integer id; + /** + * 昵称 + */ + private String name; + /** + * 性别 + */ + private Integer gender; + + public Integer getId() { + return id; + } + + public UserDTO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public UserDTO setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/pom.xml b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/pom.xml new file mode 100644 index 000000000..8bd96ee3a --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/pom.xml @@ -0,0 +1,74 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + 4.0.0 + + user-rpc-service-consumer-04 + + + + + cn.iocoder.springboot.labs + user-rpc-service-api-04 + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + org.apache.curator + curator-framework + 2.13.0 + + + org.apache.curator + curator-recipes + 2.13.0 + + + + + com.alibaba.csp + sentinel-core + 1.7.1 + + + + com.alibaba.csp + sentinel-transport-simple-http + 1.7.1 + + + + com.alibaba.csp + sentinel-apache-dubbo-adapter + 1.7.1 + + + + + diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java new file mode 100644 index 000000000..1a744ca9b --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ConsumerApplication.java @@ -0,0 +1,38 @@ +package cn.iocoder.springboot.lab30.rpc; + +import cn.iocoder.springboot.lab30.rpc.api.UserRpcService; +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; + +@SpringBootApplication +public class ConsumerApplication { + + public static void main(String[] args) { + // 启动 Spring Boot 应用 + ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); + } + + @Component + public class UserRpcServiceTest implements CommandLineRunner { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Reference(version = "${dubbo.consumer.UserRpcService.version}") + private UserRpcService userRpcService; + + @Override + public void run(String... args) throws Exception { + UserDTO user = userRpcService.get(1); + logger.info("[run][发起一次 Dubbo RPC 请求,获得用户为({})", user); + } + + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/controller/UserController.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/controller/UserController.java new file mode 100644 index 000000000..33bd391dd --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/java/cn/iocoder/springboot/lab30/rpc/controller/UserController.java @@ -0,0 +1,23 @@ +package cn.iocoder.springboot.lab30.rpc.controller; + +import cn.iocoder.springboot.lab30.rpc.api.UserRpcService; +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; +import org.apache.dubbo.config.annotation.Reference; +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; + +@RestController +@RequestMapping("/user") +public class UserController { + + @Reference(version = "${dubbo.consumer.UserRpcService.version}") + private UserRpcService userRpcService; + + @GetMapping("/get") + public UserDTO get(@RequestParam("id") Integer id) { + return userRpcService.get(id); + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/application.yaml b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/application.yaml new file mode 100644 index 000000000..8596d2028 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service-consumer # 应用名 + # Dubbo 注册中心配置 + registry: + address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 消费者配置 + consumer: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/sentinel.properties b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/sentinel.properties new file mode 100644 index 000000000..be3ba2284 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-consumer-04/src/main/resources/sentinel.properties @@ -0,0 +1 @@ +csp.sentinel.dashboard.server=127.0.0.1:7070 diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/pom.xml b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/pom.xml new file mode 100644 index 000000000..15679864b --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/pom.xml @@ -0,0 +1,74 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.1.RELEASE + + + 4.0.0 + + user-rpc-service-provider-04 + + + + + cn.iocoder.springboot.labs + user-rpc-service-api-04 + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + org.apache.curator + curator-framework + 2.13.0 + + + org.apache.curator + curator-recipes + 2.13.0 + + + + + com.alibaba.csp + sentinel-core + 1.7.1 + + + + com.alibaba.csp + sentinel-transport-simple-http + 1.7.1 + + + + com.alibaba.csp + sentinel-apache-dubbo-adapter + 1.7.1 + + + + + diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java new file mode 100644 index 000000000..2ba636636 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/ProviderApplication.java @@ -0,0 +1,14 @@ +package cn.iocoder.springboot.lab30.rpc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ProviderApplication { + + public static void main(String[] args) { + // 启动 Spring Boot 应用 + SpringApplication.run(ProviderApplication.class, args); + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java new file mode 100644 index 000000000..fe6ef676c --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/java/cn/iocoder/springboot/lab30/rpc/service/UserRpcServiceImpl.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab30.rpc.service; + +import cn.iocoder.springboot.lab30.rpc.api.UserRpcService; +import cn.iocoder.springboot.lab30.rpc.dto.UserDTO; +import org.apache.dubbo.config.annotation.Service; + +@Service(version = "${dubbo.provider.UserRpcService.version}") +public class UserRpcServiceImpl implements UserRpcService { + + @Override + public UserDTO get(Integer id) { + return new UserDTO().setId(id) + .setName("没有昵称:" + id) + .setGender(id % 2 + 1); // 1 - 男;2 - 女 + } + +} diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/application.yaml b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/application.yaml new file mode 100644 index 000000000..58798bdb5 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/application.yaml @@ -0,0 +1,20 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service-provider # 应用名 + # Dubbo 注册中心配 + registry: + address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # Dubbo 服务提供者配置 + provider: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab30.rpc.service diff --git a/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/sentinel.properties b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/sentinel.properties new file mode 100644 index 000000000..be3ba2284 --- /dev/null +++ b/lab-30/lab-30-dubbo-annotations-sentinel/user-rpc-service-provider-04/src/main/resources/sentinel.properties @@ -0,0 +1 @@ +csp.sentinel.dashboard.server=127.0.0.1:7070 diff --git a/lab-30/pom.xml b/lab-30/pom.xml index 74a96a457..c446127ce 100644 --- a/lab-30/pom.xml +++ b/lab-30/pom.xml @@ -14,6 +14,8 @@ lab-30-dubbo-xml-demo lab-30-dubbo-annotations-demo + lab-30-dubbo-annotations-nacos + lab-30-dubbo-annotations-sentinel diff --git a/lab-42/lab-42-demo02/pom.xml b/lab-42/lab-42-demo02/pom.xml new file mode 100644 index 000000000..065629430 --- /dev/null +++ b/lab-42/lab-42-demo02/pom.xml @@ -0,0 +1,46 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + 4.0.0 + + lab-42-demo02 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + 5.1.46 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.h2database + h2 + test + + + + diff --git a/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/Application.java b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/Application.java new file mode 100644 index 000000000..b96d4d52a --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/Application.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab23.testdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/controller/UserController.java b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/controller/UserController.java new file mode 100644 index 000000000..db349d20c --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/controller/UserController.java @@ -0,0 +1,33 @@ +package cn.iocoder.springboot.lab23.testdemo.controller; + +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import cn.iocoder.springboot.lab23.testdemo.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +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; + +/** + * 用户 Controller + */ +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + /** + * 获得指定用户编号的用户 + * + * @param id 用户编号 + * @return 用户 + */ + @GetMapping("/get") // URL 修改成 /get + public UserDO get(@RequestParam("id") Integer id) { + // 查询并返回用户 + return userService.get(id); + } + +} diff --git a/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDao.java b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDao.java new file mode 100644 index 000000000..2e7c5eb72 --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDao.java @@ -0,0 +1,27 @@ +package cn.iocoder.springboot.lab23.testdemo.dao; + +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.BeanPropertyRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +@Repository +public class UserDao { + + @Autowired + private JdbcTemplate template; + + public UserDO selectById(Integer id) { + return template.queryForObject("SELECT id, username, password FROM t_user WHERE id = ?", + new BeanPropertyRowMapper<>(UserDO.class), // 结果转换成对应的对象 + id); + } + + public UserDO selectByUsername(String username) { + return new UserDO().setId(1) + .setUsername(username) + .setPassword(null); + } + +} diff --git a/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dataobject/UserDO.java b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dataobject/UserDO.java new file mode 100644 index 000000000..d22dbf842 --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/dataobject/UserDO.java @@ -0,0 +1,50 @@ +package cn.iocoder.springboot.lab23.testdemo.dataobject; + +/** + * 用户 DO + */ +public class UserDO { + + /** + * 用户编号 + */ + private Integer id; + /** + * 账号 + */ + private String username; + /** + * 密码(明文) + * + * ps:生产环境下,千万不要明文噢 + */ + private String password; + + public Integer getId() { + return id; + } + + public UserDO setId(Integer id) { + this.id = id; + return this; + } + + public String getUsername() { + return username; + } + + public UserDO setUsername(String username) { + this.username = username; + return this; + } + + public String getPassword() { + return password; + } + + public UserDO setPassword(String password) { + this.password = password; + return this; + } + +} diff --git a/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/service/UserService.java b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/service/UserService.java new file mode 100644 index 000000000..be9c79785 --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/java/cn/iocoder/springboot/lab23/testdemo/service/UserService.java @@ -0,0 +1,29 @@ +package cn.iocoder.springboot.lab23.testdemo.service; + +import cn.iocoder.springboot.lab23.testdemo.dao.UserDao; +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UserService { + + @Autowired + private UserDao userDao; + + public UserDO get(Integer id) { + return userDao.selectById(id); + } + + public boolean exists(String username) { + return true; + } + + public Integer add(String username, String password) { + if (userDao.selectByUsername(username) != null) { + return null; + } + return 1; + } + +} diff --git a/lab-42/lab-42-demo02/src/main/resources/application.yaml b/lab-42/lab-42-demo02/src/main/resources/application.yaml new file mode 100644 index 000000000..0af15034a --- /dev/null +++ b/lab-42/lab-42-demo02/src/main/resources/application.yaml @@ -0,0 +1,7 @@ +spring: + # datasource 数据源配置内容 + datasource: + url: jdbc:mysql://127.0.0.1:3306/lab-39-mysql?useSSL=false&useUnicode=true&characterEncoding=UTF-8 + driver-class-name: com.mysql.jdbc.Driver + username: root + password: diff --git a/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/controller/UserControllerTest.java b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/controller/UserControllerTest.java new file mode 100644 index 000000000..f9eb0fc05 --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/controller/UserControllerTest.java @@ -0,0 +1,58 @@ +package cn.iocoder.springboot.lab23.testdemo.controller; + +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import cn.iocoder.springboot.lab23.testdemo.service.UserService; +import org.hamcrest.core.IsEqual; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +/** + * UserController 单元测试 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class UserControllerTest { + + @Autowired + private MockMvc mvc; + + @MockBean + private UserService userService; + + @Test + public void testGet() throws Exception { + // Mock UserService 的 get 方法 + Mockito.when(userService.get(1)).thenReturn( + new UserDO().setId(1).setUsername("username:1").setPassword("password:1")); + + // 查询用户 + ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get("/user/get?id=1")); + + // 校验响应状态码 + resultActions.andExpect(MockMvcResultMatchers.status().isOk()); // 响应状态码 200 + + // 校验响应内容方式一:直接全部匹配 + resultActions.andExpect(MockMvcResultMatchers.content().json("{\n" + + " \"id\": 1,\n" + + " \"username\": \"username:1\",\n" + + " \"password\": \"password:1\"\n" + + "}", true)); // 响应结果 + + // 校验响应内容方式二:逐个字段匹配 + resultActions.andExpect(MockMvcResultMatchers.jsonPath("id", IsEqual.equalTo(1))); + resultActions.andExpect(MockMvcResultMatchers.jsonPath("username", IsEqual.equalTo("username:1"))); + resultActions.andExpect(MockMvcResultMatchers.jsonPath("password", IsEqual.equalTo("password:1"))); + } + +} diff --git a/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDaoTest.java b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDaoTest.java new file mode 100644 index 000000000..081da10e6 --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/dao/UserDaoTest.java @@ -0,0 +1,33 @@ +package cn.iocoder.springboot.lab23.testdemo.dao; + +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserDaoTest { + + @Autowired + private UserDao userDao; + + @Test + @Sql(scripts = "/sql/create_tables.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(statements = "INSERT INTO `t_user`(`id`, `username`, `password`) VALUES (1, 'username:1', 'password:1');", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + public void testSelectById() { + // 查询用户 + UserDO user = userDao.selectById(1); + + // 校验结果 + Assert.assertEquals("编号不匹配", 1, (int) user.getId()); + Assert.assertEquals("用户名不匹配", "username:1", user.getUsername()); + Assert.assertEquals("密码不匹配", "password:1", user.getPassword()); + } + +} diff --git a/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/package-info.java b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/package-info.java new file mode 100644 index 000000000..ae8ba9d6c --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.springboot.lab23.testdemo; diff --git a/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest.java b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest.java new file mode 100644 index 000000000..25b9d120a --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.springboot.lab23.testdemo.service; + +import cn.iocoder.springboot.lab23.testdemo.dao.UserDao; +import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserServiceTest { + + @MockBean + private UserDao userDao; + + @Autowired + private UserService userService; + + @Test + public void testGet() { + // Mock UserDao 的 selectById 方法 + Mockito.when(userDao.selectById(1)).thenReturn( + new UserDO().setId(1).setUsername("username:1").setPassword("password:1")); + + // 查询用户 + UserDO user = userService.get(1); + + // 校验结果 + Assert.assertEquals("编号不匹配", 1, (int) user.getId()); + Assert.assertEquals("用户名不匹配", "username:1", user.getUsername()); + Assert.assertEquals("密码不匹配", "password:1", user.getPassword()); + } + +} diff --git a/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest2.java b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest2.java new file mode 100644 index 000000000..4605a0a0b --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/java/cn/iocoder/springboot/lab23/testdemo/service/UserServiceTest2.java @@ -0,0 +1,41 @@ +package cn.iocoder.springboot.lab23.testdemo.service; + +import cn.iocoder.springboot.lab23.testdemo.dao.UserDao; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserServiceTest2 { + + @Autowired + private UserService userService; + + @SpyBean + private UserDao userDao; + + @Test + public void testAddSuccess() { + System.out.println("testAddSuccess"); + // Mock UserService 的 exists 方法 + Mockito.when(userDao.selectByUsername("username")).thenReturn(null); + + Assert.assertNotNull("注册返回为 null,注册失败", + userService.add("username", "password")); + } + + @Test + public void testAddFailure() { + System.out.println("testAddFailure"); + + Assert.assertNull("注册返回为 null,注册失败", + userService.add("username", "password")); + } + +} diff --git a/lab-42/lab-42-demo02/src/test/resources/application.yaml b/lab-42/lab-42-demo02/src/test/resources/application.yaml new file mode 100644 index 000000000..382674c46 --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/resources/application.yaml @@ -0,0 +1,7 @@ +spring: + # datasource 数据源配置内容 + datasource: + url: jdbc:h2:mem:testdb + driver-class-name: org.h2.Driver + username: sa + password: diff --git a/lab-42/lab-42-demo02/src/test/resources/sql/clean.sql b/lab-42/lab-42-demo02/src/test/resources/sql/clean.sql new file mode 100644 index 000000000..be125207d --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/resources/sql/clean.sql @@ -0,0 +1 @@ +DROP TABLE `t_user` diff --git a/lab-42/lab-42-demo02/src/test/resources/sql/create_tables.sql b/lab-42/lab-42-demo02/src/test/resources/sql/create_tables.sql new file mode 100644 index 000000000..82c92d7e2 --- /dev/null +++ b/lab-42/lab-42-demo02/src/test/resources/sql/create_tables.sql @@ -0,0 +1,5 @@ +CREATE TABLE `t_user` ( + `id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号', + `username` VARCHAR(64) NOT NULL COMMENT '账号', + `password` VARCHAR(64) NOT NULL COMMENT '密码' +); diff --git a/lab-42/pom.xml b/lab-42/pom.xml index 3518bd6b5..5501dc837 100644 --- a/lab-42/pom.xml +++ b/lab-42/pom.xml @@ -13,6 +13,7 @@ pom lab-42-demo01 + lab-42-demo02 diff --git a/lab-55/lab-55-mapstruct-demo-lombok/pom.xml b/lab-55/lab-55-mapstruct-demo-lombok/pom.xml new file mode 100644 index 000000000..cb8082059 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo-lombok/pom.xml @@ -0,0 +1,65 @@ + + + + lab-55 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-55-mapstruct-demo-lombok + + + 1.8 + 1.3.1.Final + 1.18.12 + + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + + diff --git a/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java new file mode 100644 index 000000000..26775619c --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab55.mapstructdemo; + +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserBO; +import cn.iocoder.springboot.lab55.mapstructdemo.convert.UserConvert; +import cn.iocoder.springboot.lab55.mapstructdemo.dataobject.UserDO; + +public class UserBOTest { + + public static void main(String[] args) { + // 创建 UserDO 对象 + UserDO userDO = new UserDO() + .setId(1).setUsername("yudaoyuanma").setPassword("buzhidao"); + // 进行转换 + UserBO userBO = UserConvert.INSTANCE.convert(userDO); + System.out.println(userBO.getId()); + System.out.println(userBO.getUsername()); + System.out.println(userBO.getPassword()); + } + +} diff --git a/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java new file mode 100644 index 000000000..bcbfcf73d --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.bo; + +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class UserBO { + + /** 用户编号 **/ + private Integer id; + /** 用户名 **/ + private String username; + /** 密码 **/ + private String password; + +} diff --git a/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java new file mode 100644 index 000000000..5a62ca220 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java @@ -0,0 +1,15 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.convert; + +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserBO; +import cn.iocoder.springboot.lab55.mapstructdemo.dataobject.UserDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface UserConvert { + + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + + UserBO convert(UserDO userDO); + +} diff --git a/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java new file mode 100644 index 000000000..3e35cfb54 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo-lombok/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.dataobject; + + +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +public class UserDO { + + /** 用户编号 **/ + private Integer id; + /** 用户名 **/ + private String username; + /** 密码 **/ + private String password; + + public Integer getId() { + return id; + } + + public UserDO setId(Integer id) { + this.id = id; + return this; + } + + public String getUsername() { + return username; + } + + public UserDO setUsername(String username) { + this.username = username; + return this; + } + + public String getPassword() { + return password; + } + + public UserDO setPassword(String password) { + this.password = password; + return this; + } +} diff --git a/lab-55/lab-55-mapstruct-demo/pom.xml b/lab-55/lab-55-mapstruct-demo/pom.xml new file mode 100644 index 000000000..1bc9158dd --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/pom.xml @@ -0,0 +1,48 @@ + + + + lab-55 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-55-mapstruct-demo + + + 1.8 + 1.3.1.Final + + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + + + diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java new file mode 100644 index 000000000..26775619c --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserBOTest.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab55.mapstructdemo; + +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserBO; +import cn.iocoder.springboot.lab55.mapstructdemo.convert.UserConvert; +import cn.iocoder.springboot.lab55.mapstructdemo.dataobject.UserDO; + +public class UserBOTest { + + public static void main(String[] args) { + // 创建 UserDO 对象 + UserDO userDO = new UserDO() + .setId(1).setUsername("yudaoyuanma").setPassword("buzhidao"); + // 进行转换 + UserBO userBO = UserConvert.INSTANCE.convert(userDO); + System.out.println(userBO.getId()); + System.out.println(userBO.getUsername()); + System.out.println(userBO.getPassword()); + } + +} diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserDetailBOTest.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserDetailBOTest.java new file mode 100644 index 000000000..4e9742d0d --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/UserDetailBOTest.java @@ -0,0 +1,18 @@ +package cn.iocoder.springboot.lab55.mapstructdemo; + +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserDetailBO; +import cn.iocoder.springboot.lab55.mapstructdemo.convert.UserConvert; +import cn.iocoder.springboot.lab55.mapstructdemo.dataobject.UserDO; + +public class UserDetailBOTest { + + public static void main(String[] args) { + // 创建 UserDO 对象 + UserDO userDO = new UserDO() + .setId(1).setUsername("yudaoyuanma").setPassword("buzhidao"); + // 进行转换 + UserDetailBO userDetailBO = UserConvert.INSTANCE.convertDetail(userDO); + System.out.println(userDetailBO.getUserId()); + } + +} diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java new file mode 100644 index 000000000..621d63703 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserBO.java @@ -0,0 +1,39 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.bo; + +public class UserBO { + + /** 用户编号 **/ + private Integer id; + /** 用户名 **/ + private String username; + /** 密码 **/ + private String password; + + public Integer getId() { + return id; + } + + public UserBO setId(Integer id) { + this.id = id; + return this; + } + + public String getUsername() { + return username; + } + + public UserBO setUsername(String username) { + this.username = username; + return this; + } + + public String getPassword() { + return password; + } + + public UserBO setPassword(String password) { + this.password = password; + return this; + } + +} diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserDetailBO.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserDetailBO.java new file mode 100644 index 000000000..2d76a91d6 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/bo/UserDetailBO.java @@ -0,0 +1,16 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.bo; + +public class UserDetailBO { + + private Integer userId; + + public Integer getUserId() { + return userId; + } + + public UserDetailBO setUserId(Integer userId) { + this.userId = userId; + return this; + } + +} diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java new file mode 100644 index 000000000..517c47725 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/convert/UserConvert.java @@ -0,0 +1,23 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.convert; + +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserBO; +import cn.iocoder.springboot.lab55.mapstructdemo.bo.UserDetailBO; +import cn.iocoder.springboot.lab55.mapstructdemo.dataobject.UserDO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface UserConvert { + + UserConvert INSTANCE = Mappers.getMapper(UserConvert.class); + + UserBO convert(UserDO userDO); + + @Mappings({ + @Mapping(source = "id", target = "userId") + }) + UserDetailBO convertDetail(UserDO userDO); + +} diff --git a/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java new file mode 100644 index 000000000..d42b8b9a0 --- /dev/null +++ b/lab-55/lab-55-mapstruct-demo/src/main/java/cn/iocoder/springboot/lab55/mapstructdemo/dataobject/UserDO.java @@ -0,0 +1,41 @@ +package cn.iocoder.springboot.lab55.mapstructdemo.dataobject; + +/** + * 用户 DO + */ +public class UserDO { + + /** 用户编号 **/ + private Integer id; + /** 用户名 **/ + private String username; + /** 密码 **/ + private String password; + + public Integer getId() { + return id; + } + + public UserDO setId(Integer id) { + this.id = id; + return this; + } + + public String getUsername() { + return username; + } + + public UserDO setUsername(String username) { + this.username = username; + return this; + } + + public String getPassword() { + return password; + } + + public UserDO setPassword(String password) { + this.password = password; + return this; + } +} diff --git a/lab-55/pom.xml b/lab-55/pom.xml new file mode 100644 index 000000000..2b4d8ebc6 --- /dev/null +++ b/lab-55/pom.xml @@ -0,0 +1,20 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-55 + pom + + lab-55-mapstruct-demo + lab-55-mapstruct-demo-lombok + + + + diff --git "a/lab-55/\343\200\212\350\212\213\351\201\223 Spring Boot \345\257\271\350\261\241\350\275\254\346\215\242 MapStruct \345\205\245\351\227\250\343\200\213.md" "b/lab-55/\343\200\212\350\212\213\351\201\223 Spring Boot \345\257\271\350\261\241\350\275\254\346\215\242 MapStruct \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..d41942d3a --- /dev/null +++ "b/lab-55/\343\200\212\350\212\213\351\201\223 Spring Boot \345\257\271\350\261\241\350\275\254\346\215\242 MapStruct \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/lab-56/lab-56-demo01/pom.xml b/lab-56/lab-56-demo01/pom.xml new file mode 100644 index 000000000..09ac224a6 --- /dev/null +++ b/lab-56/lab-56-demo01/pom.xml @@ -0,0 +1,23 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + 4.0.0 + + lab-56-demo01 + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo01Application.java b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo01Application.java new file mode 100644 index 000000000..3f0fa7903 --- /dev/null +++ b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo01Application.java @@ -0,0 +1,14 @@ +package cn.iocoder.springboot.lab56; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Demo01Application { + + public static void main(String[] args) { + System.setProperty("server.port", "18080"); // 端口 18080 + SpringApplication.run(Demo01Application.class, args); + } + +} diff --git a/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo02Application.java b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo02Application.java new file mode 100644 index 000000000..c1c87fd38 --- /dev/null +++ b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/Demo02Application.java @@ -0,0 +1,14 @@ +package cn.iocoder.springboot.lab56; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Demo02Application { + + public static void main(String[] args) { + System.setProperty("server.port", "28080"); // 端口 28080 + SpringApplication.run(Demo02Application.class, args); + } + +} diff --git a/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/controller/DemoController.java b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/controller/DemoController.java new file mode 100644 index 000000000..d3c7e7884 --- /dev/null +++ b/lab-56/lab-56-demo01/src/main/java/cn/iocoder/springboot/lab56/controller/DemoController.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab56.controller; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + @Value("${server.port}") + private Integer serverPort; + + @GetMapping("/echo") + public String echo() { + return "echo:" + serverPort; + } + +} diff --git a/lab-56/pom.xml b/lab-56/pom.xml new file mode 100644 index 000000000..0dd12142f --- /dev/null +++ b/lab-56/pom.xml @@ -0,0 +1,19 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-56 + pom + + lab-56-demo01 + + + + diff --git "a/lab-56/\343\200\212\350\212\213\351\201\223 APISIX \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" "b/lab-56/\343\200\212\350\212\213\351\201\223 APISIX \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" new file mode 100644 index 000000000..4b5e99e62 --- /dev/null +++ "b/lab-56/\343\200\212\350\212\213\351\201\223 APISIX \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" @@ -0,0 +1 @@ + diff --git "a/lab-56/\343\200\212\350\212\213\351\201\223 Kong \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" "b/lab-56/\343\200\212\350\212\213\351\201\223 Kong \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" new file mode 100644 index 000000000..ee769ad0b --- /dev/null +++ "b/lab-56/\343\200\212\350\212\213\351\201\223 Kong \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/lab-57/lab-57-hystrix-demo01/pom.xml b/lab-57/lab-57-hystrix-demo01/pom.xml new file mode 100644 index 000000000..796d6999d --- /dev/null +++ b/lab-57/lab-57-hystrix-demo01/pom.xml @@ -0,0 +1,53 @@ + + + + lab-57 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-hystrix-demo01 + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.netflix.hystrix + hystrix-core + 1.5.18 + + + com.netflix.hystrix + hystrix-javanica + 1.5.18 + + + + + diff --git a/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/DemoApplication.java b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/DemoApplication.java new file mode 100644 index 000000000..f7d9d3098 --- /dev/null +++ b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab57.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/config/HystrixConfig.java b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/config/HystrixConfig.java new file mode 100644 index 000000000..953308fdd --- /dev/null +++ b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/config/HystrixConfig.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab57.hystrixdemo.config; + +import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +@Configuration +@EnableAspectJAutoProxy // 开启 AOP 代理的支持 +public class HystrixConfig { + + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + +} diff --git a/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/controller/DemoController.java b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/controller/DemoController.java new file mode 100644 index 000000000..a9af2c8a7 --- /dev/null +++ b/lab-57/lab-57-hystrix-demo01/src/main/java/cn/iocoder/springboot/lab57/hystrixdemo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springboot.lab57.hystrixdemo.controller; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/pom.xml b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/pom.xml new file mode 100644 index 000000000..081150fe7 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/pom.xml @@ -0,0 +1,83 @@ + + + + lab-57-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-hystrix-dubbo-demo-application + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + cn.iocoder.springboot.labs + lab-57-hystrix-dubbo-demo-user-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + com.alibaba.nacos + nacos-client + 1.2.1 + + + org.apache.dubbo + dubbo-registry-nacos + 2.7.4.1 + + + + + com.netflix.hystrix + hystrix-core + 1.5.18 + + + com.netflix.hystrix + hystrix-javanica + 1.5.18 + + + + diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java new file mode 100644 index 000000000..5ac8d8fc7 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloud.labx23.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/config/HystrixConfig.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/config/HystrixConfig.java new file mode 100644 index 000000000..7e63aed8a --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/config/HystrixConfig.java @@ -0,0 +1,17 @@ +package cn.iocoder.springcloud.labx23.demo.config; + +import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +@Configuration +@EnableAspectJAutoProxy // 开启 AOP 代理的支持 +public class HystrixConfig { + + @Bean + public HystrixCommandAspect hystrixCommandAspect() { + return new HystrixCommandAspect(); + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java new file mode 100644 index 000000000..60507e23b --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springcloud.labx23.demo.controller; + +import cn.iocoder.springboot.lab57.userservice.api.UserService; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Reference(protocol = "dubbo", version = "1.0.0") + private UserService userService; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return userService.getUser(id); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/resources/application.yaml b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/resources/application.yaml new file mode 100644 index 000000000..6a6e27483 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-application/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: demo-consumer # 应用名 + # Dubbo 注册中心配置 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 消费者配置 + consumer: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/pom.xml b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/pom.xml new file mode 100644 index 000000000..081ce7cbe --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + lab-57-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-hystrix-dubbo-demo-user-service-api + + diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab57/userservice/api/UserService.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab57/userservice/api/UserService.java new file mode 100644 index 000000000..71bba3d32 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab57/userservice/api/UserService.java @@ -0,0 +1,7 @@ +package cn.iocoder.springboot.lab57.userservice.api; + +public interface UserService { + + String getUser(Integer id); + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/pom.xml b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/pom.xml new file mode 100644 index 000000000..d2ece2768 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/pom.xml @@ -0,0 +1,71 @@ + + + + lab-57-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-hystrix-dubbo-demo-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + cn.iocoder.springboot.labs + lab-57-hystrix-dubbo-demo-user-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + com.alibaba.nacos + nacos-client + 1.2.1 + + + org.apache.dubbo + dubbo-registry-nacos + 2.7.4.1 + + + + diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java new file mode 100644 index 000000000..ddd1aef21 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab57.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(UserServiceApplication.class); + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/service/UserServiceImpl.java b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/service/UserServiceImpl.java new file mode 100644 index 000000000..a546d32a6 --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/service/UserServiceImpl.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab57.userservice.service; + +import cn.iocoder.springboot.lab57.userservice.api.UserService; + +@org.apache.dubbo.config.annotation.Service(version = "1.0.0") +public class UserServiceImpl implements UserService { + + @Override + public String getUser(Integer id) { + return "User:" + id; + } + +} diff --git a/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml new file mode 100644 index 000000000..ba2c3030e --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/lab-57-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml @@ -0,0 +1,20 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # Dubbo 服务提供者配置 + provider: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + UserRpcService: + version: 1.0.0 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab57.userservice.service diff --git a/lab-57/lab-57-hystrix-dubbo-demo/pom.xml b/lab-57/lab-57-hystrix-dubbo-demo/pom.xml new file mode 100644 index 000000000..d58a5549f --- /dev/null +++ b/lab-57/lab-57-hystrix-dubbo-demo/pom.xml @@ -0,0 +1,22 @@ + + + + lab-57 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-hystrix-dubbo-demo + pom + + + lab-57-hystrix-dubbo-demo-user-service + lab-57-hystrix-dubbo-demo-user-service-api + lab-57-hystrix-dubbo-demo-application + + + + diff --git a/lab-57/lab-57-user-service/pom.xml b/lab-57/lab-57-user-service/pom.xml new file mode 100644 index 000000000..0040aae34 --- /dev/null +++ b/lab-57/lab-57-user-service/pom.xml @@ -0,0 +1,40 @@ + + + + lab-57 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/lab-57/lab-57-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java b/lab-57/lab-57-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java new file mode 100644 index 000000000..18047b209 --- /dev/null +++ b/lab-57/lab-57-user-service/src/main/java/cn/iocoder/springboot/lab57/userservice/UserServiceApplication.java @@ -0,0 +1,40 @@ +package cn.iocoder.springboot.lab57.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +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; +import java.util.stream.Collectors; + +@SpringBootApplication +public class UserServiceApplication { + + @RestController + @RequestMapping("/user") + public class UserController { + + @GetMapping("/get") + public String get(@RequestParam("id") Integer id) { + return "User:" + id; + } + + @GetMapping("/batch_get") + public List batchGet(@RequestParam("ids") List ids) { + return ids.stream().map(id -> "User:" + id).collect(Collectors.toList()); + } + + } + + public static void main(String[] args) { + // 设置端口 + System.setProperty("server.port", "18080"); + + // 应用启动 + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/lab-57/pom.xml b/lab-57/pom.xml new file mode 100644 index 000000000..4a2dfee4c --- /dev/null +++ b/lab-57/pom.xml @@ -0,0 +1,20 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-57 + pom + + lab-57-user-service + lab-57-hystrix-demo01 + lab-57-hystrix-dubbo-demo + + + diff --git "a/lab-57/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" "b/lab-57/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..fcbb42af1 --- /dev/null +++ "b/lab-57/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/lab-58/lab-58-feign-demo/pom.xml b/lab-58/lab-58-feign-demo/pom.xml new file mode 100644 index 000000000..454547be2 --- /dev/null +++ b/lab-58/lab-58-feign-demo/pom.xml @@ -0,0 +1,59 @@ + + + + lab-58 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-58-feign-demo + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.github.openfeign + feign-core + 11.0 + + + + io.github.openfeign + feign-gson + 11.0 + + + + io.github.openfeign + feign-spring4 + 11.0 + + + + diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/FeignDemoApplication.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/FeignDemoApplication.java new file mode 100644 index 000000000..99ab6cd1a --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/FeignDemoApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab58.feigndemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FeignDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(FeignDemoApplication.class, args); + } + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/config/FeignConfig.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/config/FeignConfig.java new file mode 100644 index 000000000..c6dab2676 --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/config/FeignConfig.java @@ -0,0 +1,32 @@ +package cn.iocoder.springboot.lab58.feigndemo.config; + +import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient; +import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient02; +import feign.Feign; +import feign.gson.GsonDecoder; +import feign.gson.GsonEncoder; +import feign.spring.SpringContract; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class FeignConfig { + + @Bean + public UserServiceFeignClient userServiceFeignClient() { + return Feign.builder() + .encoder(new GsonEncoder()) + .decoder(new GsonDecoder()) + .target(UserServiceFeignClient.class, "http://127.0.0.1:18080"); // 目标地址 + } + + @Bean + public UserServiceFeignClient02 userServiceFeignClient02() { + return Feign.builder() + .encoder(new GsonEncoder()) + .decoder(new GsonDecoder()) + .contract(new SpringContract()) + .target(UserServiceFeignClient02.class, "http://127.0.0.1:18080"); // 目标地址 + } + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController.java new file mode 100644 index 000000000..c15050d7b --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController.java @@ -0,0 +1,48 @@ +package cn.iocoder.springboot.lab58.feigndemo.controller; + +import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient; +import cn.iocoder.springboot.lab58.feigndemo.feign.request.UserAddRequest; +import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + @Autowired + private UserServiceFeignClient userServiceFeignClient; + + @GetMapping("/test01") + public UserResponse test01() { + return userServiceFeignClient.get(1); +// System.out.println("编号:" + user.getId()); +// System.out.println("昵称:" + user.getName()); +// System.out.println("性别:" + user.getGender()); + } + + @GetMapping("/test02A") + public List test02A() { + return userServiceFeignClient.list("你猜", 1); + } + + @GetMapping("/test02B") + public List test02B() { + Map queryMap = new HashMap<>(); + queryMap.put("name", "昵称"); + return userServiceFeignClient.list(queryMap); + } + + @GetMapping("/test03") + public Integer test03() { + return userServiceFeignClient.add(new UserAddRequest() + .setName("昵称").setGender(1)); + } + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController02.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController02.java new file mode 100644 index 000000000..755d74188 --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/controller/DemoController02.java @@ -0,0 +1,46 @@ +package cn.iocoder.springboot.lab58.feigndemo.controller; + +import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient02; +import cn.iocoder.springboot.lab58.feigndemo.feign.request.UserAddRequest; +import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/demo02") +public class DemoController02 { + + @Autowired + private UserServiceFeignClient02 userServiceFeignClient; + + @GetMapping("/test01") + public UserResponse test01() { + return userServiceFeignClient.get(1); +// System.out.println("编号:" + user.getId()); +// System.out.println("昵称:" + user.getName()); +// System.out.println("性别:" + user.getGender()); + } + + @GetMapping("/test02A") + public List test02A() { + return userServiceFeignClient.list("你猜", null); + } + +// @GetMapping("/test02B") +// public List test02B() { +// Map queryMap = new HashMap<>(); +// queryMap.put("name", "昵称"); +// return userServiceFeignClient.list(queryMap); +// } + + @GetMapping("/test03") + public Integer test03() { + return userServiceFeignClient.add(new UserAddRequest() + .setName("昵称").setGender(1)); + } + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient.java new file mode 100644 index 000000000..d5c88c66e --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient.java @@ -0,0 +1,30 @@ +package cn.iocoder.springboot.lab58.feigndemo.feign; + +import cn.iocoder.springboot.lab58.feigndemo.feign.request.UserAddRequest; +import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse; +import feign.*; + +import java.util.List; +import java.util.Map; + +/** + * 基于 Contract.Default 默认契约 + */ +public interface UserServiceFeignClient { + + // 获得用户详情 + @RequestLine("GET /user/get?id={id}") + UserResponse get(@Param("id") Integer id); + + @RequestLine("GET /user/list?name={name}&gender={gender}") + List list(@Param("name") String name, + @Param("gender") Integer gender); + + @RequestLine("GET /user/list") + List list(@QueryMap Map queryMap); + + @RequestLine("POST /user/add") + @Headers("Content-Type: application/json") + Integer add(UserAddRequest request); + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient02.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient02.java new file mode 100644 index 000000000..7bbd980c2 --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/UserServiceFeignClient02.java @@ -0,0 +1,31 @@ +package cn.iocoder.springboot.lab58.feigndemo.feign; + +import cn.iocoder.springboot.lab58.feigndemo.feign.request.UserAddRequest; +import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +/** + * 基于 SpringContract 拓展契约 + */ +public interface UserServiceFeignClient02 { + + // 获得用户详情 + @GetMapping("/user/get") + UserResponse get(@RequestParam("id") Integer id); + + @GetMapping("/user/list") + List list(@RequestParam("name") String name, + @RequestParam("gender") Integer gender); + +// @RequestLine("GET /user/list") +// List list(@QueryMap Map queryMap); + + @PostMapping(value = "/user/add", consumes = "application/json") + Integer add(@RequestBody UserAddRequest request); + +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/request/UserAddRequest.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/request/UserAddRequest.java new file mode 100644 index 000000000..bafa03834 --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/request/UserAddRequest.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab58.feigndemo.feign.request; + +/** + * User 添加 Request + */ +public class UserAddRequest { + + private String name; + private Integer gender; + + public String getName() { + return name; + } + + public UserAddRequest setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserAddRequest setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/response/UserResponse.java b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/response/UserResponse.java new file mode 100644 index 000000000..8d47e8dd5 --- /dev/null +++ b/lab-58/lab-58-feign-demo/src/main/java/cn/iocoder/springboot/lab58/feigndemo/feign/response/UserResponse.java @@ -0,0 +1,36 @@ +package cn.iocoder.springboot.lab58.feigndemo.feign.response; + +public class UserResponse { + + private Integer id; + private String name; + private Integer gender; + + public Integer getId() { + return id; + } + + public UserResponse setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public UserResponse setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserResponse setGender(Integer gender) { + this.gender = gender; + return this; + } + +} diff --git a/lab-58/lab-58-user-service/pom.xml b/lab-58/lab-58-user-service/pom.xml new file mode 100644 index 000000000..4f8d500ff --- /dev/null +++ b/lab-58/lab-58-user-service/pom.xml @@ -0,0 +1,40 @@ + + + + lab-58 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-58-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/UserServiceApplication.java b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/UserServiceApplication.java new file mode 100644 index 000000000..44a947a9c --- /dev/null +++ b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/UserServiceApplication.java @@ -0,0 +1,17 @@ +package cn.iocoder.springboot.lab58.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserServiceApplication { + + public static void main(String[] args) { + // 设置端口 + System.setProperty("server.port", "18080"); + + // 应用启动 + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/controller/UserController.java b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/controller/UserController.java new file mode 100644 index 000000000..c0e2a0901 --- /dev/null +++ b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/controller/UserController.java @@ -0,0 +1,38 @@ +package cn.iocoder.springboot.lab58.userservice.controller; + +import cn.iocoder.springboot.lab58.userservice.request.UserAddRequest; +import cn.iocoder.springboot.lab58.userservice.response.UserResponse; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +@RestController +@RequestMapping("/user") +public class UserController { + + @GetMapping("/get") // 获得指定用户 + public UserResponse get(@RequestParam("id") Integer id) { + return new UserResponse().setId(id) + .setName("昵称:" + id).setGender(id % 2 == 0 ? 1 : 2); + } + + @GetMapping("/list") // 获得匹配的用户列表 + public List list(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "gender", required = false) Integer gender) { + List users = new ArrayList<>(); + for (int id = 1; id <= 3; id++) { + users.add(new UserResponse().setId(id) + .setName(name + "_" + id).setGender(gender)); + } + return users; + } + + @PostMapping("/add") // 添加用户 + public Integer add(@RequestBody UserAddRequest request) { + System.out.println("昵称:" + request.getName()); + System.out.println("性别:" + request.getGender()); + return 1; + } + +} diff --git a/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/request/UserAddRequest.java b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/request/UserAddRequest.java new file mode 100644 index 000000000..931434c75 --- /dev/null +++ b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/request/UserAddRequest.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab58.userservice.request; + +/** + * User 添加 Request + */ +public class UserAddRequest { + + private String name; + private Integer gender; + + public String getName() { + return name; + } + + public UserAddRequest setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserAddRequest setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/response/UserResponse.java b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/response/UserResponse.java new file mode 100644 index 000000000..bb1b4375e --- /dev/null +++ b/lab-58/lab-58-user-service/src/main/java/cn/iocoder/springboot/lab58/userservice/response/UserResponse.java @@ -0,0 +1,38 @@ +package cn.iocoder.springboot.lab58.userservice.response; + +/** + * User 信息 Response + */ +public class UserResponse { + + private Integer id; + private String name; + private Integer gender; + + public Integer getId() { + return id; + } + + public UserResponse setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public UserResponse setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserResponse setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-58/pom.xml b/lab-58/pom.xml new file mode 100644 index 000000000..a194fa03b --- /dev/null +++ b/lab-58/pom.xml @@ -0,0 +1,20 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-58 + pom + + + lab-58-user-service + lab-58-feign-demo + + + diff --git "a/lab-58/\343\200\212\350\212\213\351\201\223 Spring Boot \345\243\260\346\230\216\345\274\217\350\260\203\347\224\250 Feign \345\205\245\351\227\250\343\200\213.md" "b/lab-58/\343\200\212\350\212\213\351\201\223 Spring Boot \345\243\260\346\230\216\345\274\217\350\260\203\347\224\250 Feign \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..b694cce33 --- /dev/null +++ "b/lab-58/\343\200\212\350\212\213\351\201\223 Spring Boot \345\243\260\346\230\216\345\274\217\350\260\203\347\224\250 Feign \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/lab-59/lab-59-resilience4j-actuator/pom.xml b/lab-59/lab-59-resilience4j-actuator/pom.xml new file mode 100644 index 000000000..9f7c46375 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/pom.xml @@ -0,0 +1,65 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-59-resilience4j-actuator + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.github.resilience4j + resilience4j-spring-boot2 + 1.4.0 + + + + + org.aspectj + aspectjrt + 1.9.5 + + + org.aspectj + aspectjweaver + 1.9.5 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java new file mode 100644 index 000000000..9f482e9d1 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java new file mode 100644 index 000000000..6937108ac --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java @@ -0,0 +1,30 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/bulkhead-demo") +public class BulkheadDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @Bulkhead(name = "backendC", fallbackMethod = "getUserFallback", type = Bulkhead.Type.SEMAPHORE) + public String getUser(@RequestParam("id") Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java new file mode 100644 index 000000000..37882518e --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @CircuitBreaker(name = "backendA", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java new file mode 100644 index 000000000..51f1b5612 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/rate-limiter-demo") +public class RateLimiterDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @RateLimiter(name = "backendB", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java new file mode 100644 index 000000000..23014c4a8 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.retry.annotation.Retry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/retry-demo") +public class RetryDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @Retry(name = "backendE", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java new file mode 100644 index 000000000..8f27bb86e --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/thread-pool-bulkhead-demo") +public class ThreadPoolBulkheadDemoController { + + @Autowired + private ThreadPoolBulkheadService threadPoolBulkheadService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + threadPoolBulkheadService.getUser0(id); + return threadPoolBulkheadService.getUser0(id).get(); + } + + @Service + public static class ThreadPoolBulkheadService { + + private Logger logger = LoggerFactory.getLogger(ThreadPoolBulkheadService.class); + + @Bulkhead(name = "backendD", fallbackMethod = "getUserFallback", type = Bulkhead.Type.THREADPOOL) + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java new file mode 100644 index 000000000..5c1f35d44 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/time-limiter-demo") +public class TimeLimiterDemoController { + + @Autowired + private TimeLimiterService timeLimiterService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + return timeLimiterService.getUser0(id).get(); + } + + @Service + public static class TimeLimiterService { + + private Logger logger = LoggerFactory.getLogger(TimeLimiterService.class); + + @Bulkhead(name = "backendD", type = Bulkhead.Type.THREADPOOL) + @TimeLimiter(name = "backendF", fallbackMethod = "getUserFallback") + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + +} diff --git a/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml b/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml new file mode 100644 index 000000000..d3736cfa2 --- /dev/null +++ b/lab-59/lab-59-resilience4j-actuator/src/main/resources/application.yml @@ -0,0 +1,66 @@ +resilience4j: + # Resilience4j 的断路器配置项,对应 CircuitBreakerProperties 属性类 + circuitbreaker: + instances: + backendA: + failure-rate-threshold: 50 # 熔断器关闭状态和半开状态使用的同一个失败率阈值,单位:百分比。默认为 50 + ring-buffer-size-in-closed-state: 5 # 熔断器关闭状态的缓冲区大小,不会限制线程的并发量,在熔断器发生状态转换前所有请求都会调用后端服务。默认为 100 + ring-buffer-size-in-half-open-state: 5 # 熔断器半开状态的缓冲区大小,会限制线程的并发量。例如,缓冲区为 10 则每次只会允许 10 个请求调用后端服务。默认为 10 + wait-duration-in-open-state : 5000 # 熔断器从打开状态转变为半开状态等待的时间,单位:微秒 + automatic-transition-from-open-to-half-open-enabled: true # 如果置为 true,当等待时间结束会自动由打开变为半开;若置为 false,则需要一个请求进入来触发熔断器状态转换。默认为 true + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的限流器配置项,对应 RateLimiterProperties 属性类 + ratelimiter: + instances: + backendB: + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 + limit-refresh-period: 10s # 每个周期的时长,单位:微秒。默认为 500 + timeout-duration: 5s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的信号量 Bulkhead 配置项,对应 BulkheadConfigurationProperties 属性类 + bulkhead: + instances: + backendC: + max-concurrent-calls: 1 # 并发调用数。默认为 25 + max-wait-duration: 5s # 并发调用到达上限时,阻塞等待的时长,单位:微秒。默认为 0 + # Resilience4j 的线程池 Bulkhead 配置项,对应 ThreadPoolBulkheadProperties 属性类 + thread-pool-bulkhead: + instances: + backendD: + max-thread-pool-size: 1 # 线程池的最大大小。默认为 Runtime.getRuntime().availableProcessors() + core-thread-pool-size: 1 # 线程池的核心大小。默认为 Runtime.getRuntime().availableProcessors() - 1 + queue-capacity: 200 # 线程池的队列大小。默认为 100 + keep-alive-duration: 100s # 超过核心大小的线程,空闲存活时间。默认为 20 毫秒 + + # Resilience4j 的重试 Retry 配置项,对应 RetryProperties 属性类 + retry: + instances: + backendE: + max-retry-Attempts: 3 # 最大重试次数。默认为 3 + wait-duration: 5s # 下次重试的间隔,单位:微秒。默认为 500 毫秒 + retry-exceptions: # 需要重试的异常列表。默认为空 + ingore-exceptions: # 需要忽略的异常列表。默认为空 + + # Resilience4j 的超时限制器 TimeLimiter 配置项,对应 TimeLimiterProperties 属性类 + timelimiter: + instances: + backendF: + timeout-duration: 1s # 等待超时时间,单位:微秒。默认为 1 秒 + cancel-running-future: true # 当等待超时时,是否关闭取消线程。默认为 true + +management: + endpoints: + # Actuator HTTP 配置项,对应 WebEndpointProperties 配置类 + web: + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + endpoint: + # Health 端点配置项,对应 HealthProperties 配置类 + health: + show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。 + # 健康检查配置项 + health: + circuitbreakers.enabled: true + ratelimiters.enabled: true diff --git a/lab-59/lab-59-resilience4j-demo01/pom.xml b/lab-59/lab-59-resilience4j-demo01/pom.xml new file mode 100644 index 000000000..09f31b342 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/pom.xml @@ -0,0 +1,60 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-59-resilience4j-demo01 + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.github.resilience4j + resilience4j-spring-boot2 + 1.4.0 + + + + + org.aspectj + aspectjrt + 1.9.5 + + + org.aspectj + aspectjweaver + 1.9.5 + + + + + diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java new file mode 100644 index 000000000..9f482e9d1 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java new file mode 100644 index 000000000..6937108ac --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/BulkheadDemoController.java @@ -0,0 +1,30 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/bulkhead-demo") +public class BulkheadDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @Bulkhead(name = "backendC", fallbackMethod = "getUserFallback", type = Bulkhead.Type.SEMAPHORE) + public String getUser(@RequestParam("id") Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java new file mode 100644 index 000000000..37882518e --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/DemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @CircuitBreaker(name = "backendA", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java new file mode 100644 index 000000000..51f1b5612 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RateLimiterDemoController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/rate-limiter-demo") +public class RateLimiterDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @RateLimiter(name = "backendB", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java new file mode 100644 index 000000000..23014c4a8 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/RetryDemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.retry.annotation.Retry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/retry-demo") +public class RetryDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @Retry(name = "backendE", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java new file mode 100644 index 000000000..8f27bb86e --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/ThreadPoolBulkheadDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/thread-pool-bulkhead-demo") +public class ThreadPoolBulkheadDemoController { + + @Autowired + private ThreadPoolBulkheadService threadPoolBulkheadService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + threadPoolBulkheadService.getUser0(id); + return threadPoolBulkheadService.getUser0(id).get(); + } + + @Service + public static class ThreadPoolBulkheadService { + + private Logger logger = LoggerFactory.getLogger(ThreadPoolBulkheadService.class); + + @Bulkhead(name = "backendD", fallbackMethod = "getUserFallback", type = Bulkhead.Type.THREADPOOL) + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java new file mode 100644 index 000000000..5c1f35d44 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/java/cn/iocoder/springboot/lab59/resillience4jdemo/controller/TimeLimiterDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springboot.lab59.resillience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/time-limiter-demo") +public class TimeLimiterDemoController { + + @Autowired + private TimeLimiterService timeLimiterService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + return timeLimiterService.getUser0(id).get(); + } + + @Service + public static class TimeLimiterService { + + private Logger logger = LoggerFactory.getLogger(TimeLimiterService.class); + + @Bulkhead(name = "backendD", type = Bulkhead.Type.THREADPOOL) + @TimeLimiter(name = "backendF", fallbackMethod = "getUserFallback") + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + +} diff --git a/lab-59/lab-59-resilience4j-demo01/src/main/resources/application.yml b/lab-59/lab-59-resilience4j-demo01/src/main/resources/application.yml new file mode 100644 index 000000000..6a5b2ad75 --- /dev/null +++ b/lab-59/lab-59-resilience4j-demo01/src/main/resources/application.yml @@ -0,0 +1,51 @@ +resilience4j: + # Resilience4j 的断路器配置项,对应 CircuitBreakerProperties 属性类 + circuitbreaker: + instances: + backendA: + failure-rate-threshold: 50 # 熔断器关闭状态和半开状态使用的同一个失败率阈值,单位:百分比。默认为 50 + ring-buffer-size-in-closed-state: 5 # 熔断器关闭状态的缓冲区大小,不会限制线程的并发量,在熔断器发生状态转换前所有请求都会调用后端服务。默认为 100 + ring-buffer-size-in-half-open-state: 5 # 熔断器半开状态的缓冲区大小,会限制线程的并发量。例如,缓冲区为 10 则每次只会允许 10 个请求调用后端服务。默认为 10 + wait-duration-in-open-state : 5000 # 熔断器从打开状态转变为半开状态等待的时间,单位:微秒 + automatic-transition-from-open-to-half-open-enabled: true # 如果置为 true,当等待时间结束会自动由打开变为半开;若置为 false,则需要一个请求进入来触发熔断器状态转换。默认为 true + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的限流器配置项,对应 RateLimiterProperties 属性类 + ratelimiter: + instances: + backendB: + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 + limit-refresh-period: 10s # 每个周期的时长,单位:微秒。默认为 500 + timeout-duration: 5s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的信号量 Bulkhead 配置项,对应 BulkheadConfigurationProperties 属性类 + bulkhead: + instances: + backendC: + max-concurrent-calls: 1 # 并发调用数。默认为 25 + max-wait-duration: 5s # 并发调用到达上限时,阻塞等待的时长,单位:微秒。默认为 0 + # Resilience4j 的线程池 Bulkhead 配置项,对应 ThreadPoolBulkheadProperties 属性类 + thread-pool-bulkhead: + instances: + backendD: + max-thread-pool-size: 1 # 线程池的最大大小。默认为 Runtime.getRuntime().availableProcessors() + core-thread-pool-size: 1 # 线程池的核心大小。默认为 Runtime.getRuntime().availableProcessors() - 1 + queue-capacity: 200 # 线程池的队列大小。默认为 100 + keep-alive-duration: 100s # 超过核心大小的线程,空闲存活时间。默认为 20 毫秒 + + # Resilience4j 的重试 Retry 配置项,对应 RetryProperties 属性类 + retry: + instances: + backendE: + max-retry-Attempts: 3 # 最大重试次数。默认为 3 + wait-duration: 5s # 下次重试的间隔,单位:微秒。默认为 500 毫秒 + retry-exceptions: # 需要重试的异常列表。默认为空 + ingore-exceptions: # 需要忽略的异常列表。默认为空 + + # Resilience4j 的超时限制器 TimeLimiter 配置项,对应 TimeLimiterProperties 属性类 + timelimiter: + instances: + backendF: + timeout-duration: 1s # 等待超时时间,单位:微秒。默认为 1 秒 + cancel-running-future: true # 当等待超时时,是否关闭取消线程。默认为 true diff --git a/lab-59/lab-59-user-service/pom.xml b/lab-59/lab-59-user-service/pom.xml new file mode 100644 index 000000000..eb3722950 --- /dev/null +++ b/lab-59/lab-59-user-service/pom.xml @@ -0,0 +1,40 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-59-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/lab-59/lab-59-user-service/src/main/java/cn/iocoder/springboot/lab59/userservice/UserServiceApplication.java b/lab-59/lab-59-user-service/src/main/java/cn/iocoder/springboot/lab59/userservice/UserServiceApplication.java new file mode 100644 index 000000000..fdbd7a1ab --- /dev/null +++ b/lab-59/lab-59-user-service/src/main/java/cn/iocoder/springboot/lab59/userservice/UserServiceApplication.java @@ -0,0 +1,40 @@ +package cn.iocoder.springboot.lab59.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +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; +import java.util.stream.Collectors; + +@SpringBootApplication +public class UserServiceApplication { + + @RestController + @RequestMapping("/user") + public class UserController { + + @GetMapping("/get") + public String get(@RequestParam("id") Integer id) { + return "User:" + id; + } + + @GetMapping("/batch_get") + public List batchGet(@RequestParam("ids") List ids) { + return ids.stream().map(id -> "User:" + id).collect(Collectors.toList()); + } + + } + + public static void main(String[] args) { + // 设置端口 + System.setProperty("server.port", "18080"); + + // 应用启动 + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/lab-59/pom.xml b/lab-59/pom.xml new file mode 100644 index 000000000..c9b5e4863 --- /dev/null +++ b/lab-59/pom.xml @@ -0,0 +1,21 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-59 + pom + + + lab-59-user-service + lab-59-resilience4j-demo01 + lab-59-resilience4j-actuator + + + diff --git "a/lab-59/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" "b/lab-59/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..24f442c17 --- /dev/null +++ "b/lab-59/\343\200\212\350\212\213\351\201\223 Spring Boot \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/pom.xml b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/pom.xml new file mode 100644 index 000000000..998e8659b --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + lab-60-soul-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60-soul-dubbo-demo-user-service-api + + diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/UserService.java b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/UserService.java new file mode 100644 index 000000000..181223a9a --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/UserService.java @@ -0,0 +1,11 @@ +package cn.iocoder.springboot.lab60.userservice.api; + +import cn.iocoder.springboot.lab60.userservice.api.dto.UserCreateDTO; + +public interface UserService { + + String getUser(Integer id); + + Integer createUser(UserCreateDTO createDTO); + +} diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/dto/UserCreateDTO.java b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/dto/UserCreateDTO.java new file mode 100644 index 000000000..9fa4774d2 --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springboot/lab60/userservice/api/dto/UserCreateDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab60.userservice.api.dto; + +/** + * 用户创建 DTO + */ +public class UserCreateDTO { + + /** + * 昵称 + */ + private String nickname; + /** + * 性别 + */ + private Integer gender; + + public String getNickname() { + return nickname; + } + + public UserCreateDTO setNickname(String nickname) { + this.nickname = nickname; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserCreateDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/pom.xml b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/pom.xml new file mode 100644 index 000000000..ada8bc2fd --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/pom.xml @@ -0,0 +1,79 @@ + + + + lab-60-soul-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60-soul-dubbo-demo-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + cn.iocoder.springboot.labs + lab-60-soul-dubbo-demo-user-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter + + + + + org.apache.dubbo + dubbo + 2.7.4.1 + + + org.apache.dubbo + dubbo-spring-boot-starter + 2.7.4.1 + + + + + com.alibaba.nacos + nacos-client + 1.2.1 + + + org.apache.dubbo + dubbo-registry-nacos + 2.7.4.1 + + + + + org.dromara + soul-client-apache-dubbo + 2.1.2-RELEASE + + + + + diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/UserServiceApplication.java b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/UserServiceApplication.java new file mode 100644 index 000000000..0a4869891 --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/UserServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab60.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(UserServiceApplication.class); + } + +} diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/service/UserServiceImpl.java b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/service/UserServiceImpl.java new file mode 100644 index 000000000..fa6e1f1c8 --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/java/cn/iocoder/springboot/lab60/userservice/service/UserServiceImpl.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab60.userservice.service; + +import cn.iocoder.springboot.lab60.userservice.api.UserService; +import cn.iocoder.springboot.lab60.userservice.api.dto.UserCreateDTO; +import org.dromara.soul.client.common.annotation.SoulClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@org.apache.dubbo.config.annotation.Service(version = "1.0.0") +public class UserServiceImpl implements UserService { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + @SoulClient(path = "/user/get", desc = "获得用户详细") + public String getUser(Integer id) { + return "User:" + id; + } + + @Override + @SoulClient(path = "/user/create", desc = "创建用户") + public Integer createUser(UserCreateDTO createDTO) { + logger.info("[createUser][username({}) password({})]", createDTO.getNickname(), createDTO.getGender()); + return 1; + } + +} + diff --git a/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/resources/application.yaml b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/resources/application.yaml new file mode 100644 index 000000000..c39d18bfb --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/lab-60-soul-dubbo-demo-user-service/src/main/resources/application.yaml @@ -0,0 +1,26 @@ +# dubbo 配置项,对应 DubboConfigurationProperties 配置类 +dubbo: + # Dubbo 应用配置 + application: + name: user-service # 应用名 + # Dubbo 注册中心配 + registry: + address: nacos://127.0.0.1:8848 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。 + # Dubbo 服务提供者协议配置 + protocol: + port: -1 # 协议端口。使用 -1 表示随机端口。 + name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档 + # Dubbo 服务提供者配置 + provider: + timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改 + # 配置扫描 Dubbo 自定义的 @Service 注解,暴露成 Dubbo 服务提供者 + scan: + base-packages: cn.iocoder.springboot.lab60.userservice.service + +soul: + # Soul 针对 Dubbo 的配置项,对应 DubboConfig 配置类 + dubbo: + admin-url: http://127.0.0.1:9095 # Soul Admin 地址 + context-path: /user-api # 设置在 Soul 网关的路由前缀,例如说 /order、/product 等等。 + # 后续,网关会根据该 context-path 来进行路由 + app-name: user-service # 应用名。未配置情况下,默认使用 Dubbo 的应用名 diff --git a/lab-60/lab-60-soul-dubbo-demo/pom.xml b/lab-60/lab-60-soul-dubbo-demo/pom.xml new file mode 100644 index 000000000..f833523de --- /dev/null +++ b/lab-60/lab-60-soul-dubbo-demo/pom.xml @@ -0,0 +1,20 @@ + + + + lab-60 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60-soul-dubbo-demo + pom + + + lab-60-soul-dubbo-demo-user-service-api + lab-60-soul-dubbo-demo-user-service + + + diff --git a/lab-60/lab-60-soul-spring-boot-demo/pom.xml b/lab-60/lab-60-soul-spring-boot-demo/pom.xml new file mode 100644 index 000000000..ae07cb058 --- /dev/null +++ b/lab-60/lab-60-soul-spring-boot-demo/pom.xml @@ -0,0 +1,47 @@ + + + + lab-60 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60-soul-spring-boot-demo + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.dromara + soul-client-springmvc + 2.1.2-RELEASE + + + + diff --git a/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/DemoApplication.java b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/DemoApplication.java new file mode 100644 index 000000000..bf581bae0 --- /dev/null +++ b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/DemoApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springboot.lab60; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/controller/UserController.java b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/controller/UserController.java new file mode 100644 index 000000000..0b6bee6c2 --- /dev/null +++ b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/controller/UserController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springboot.lab60.controller; + +import cn.iocoder.springboot.lab60.dto.UserCreateDTO; +import org.dromara.soul.client.common.annotation.SoulClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/user") +public class UserController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get") + @SoulClient(path = "/user/get", desc = "获得用户详细") + public String getUser(@RequestParam("id") Integer id) { + return "DEMO:" + id; + } + + @PostMapping("/create") + @SoulClient(path = "/user/create", desc = "创建用户") + public Integer createUser(@RequestBody UserCreateDTO createDTO) { + logger.info("[createUser][username({}) password({})]", createDTO.getNickname(), createDTO.getGender()); + return 1; + } + +} diff --git a/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/dto/UserCreateDTO.java b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/dto/UserCreateDTO.java new file mode 100644 index 000000000..0c01f8ac5 --- /dev/null +++ b/lab-60/lab-60-soul-spring-boot-demo/src/main/java/cn/iocoder/springboot/lab60/dto/UserCreateDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.springboot.lab60.dto; + +/** + * 用户创建 DTO + */ +public class UserCreateDTO { + + /** + * 昵称 + */ + private String nickname; + /** + * 性别 + */ + private Integer gender; + + public String getNickname() { + return nickname; + } + + public UserCreateDTO setNickname(String nickname) { + this.nickname = nickname; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserCreateDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-60/lab-60-soul-spring-boot-demo/src/main/resources/application.yaml b/lab-60/lab-60-soul-spring-boot-demo/src/main/resources/application.yaml new file mode 100644 index 000000000..1034cd123 --- /dev/null +++ b/lab-60/lab-60-soul-spring-boot-demo/src/main/resources/application.yaml @@ -0,0 +1,8 @@ +soul: + # Soul 针对 SpringMVC 的配置项,对应 SoulHttpConfig 配置类 + http: + admin-url: http://127.0.0.1:9095 # Soul Admin 地址 + context-path: /sb-demo-api # 设置在 Soul 网关的路由前缀,例如说 /order、/product 等等。 + # 后续,网关会根据该 context-path 来进行路由 + app-name: sb-demo-service # 应用名。未配置情况下,默认使用 `spring.application.name` 配置项 + zookeeper-url: 127.0.0.1:2181 # 使用 Zookeeper 作为注册中心的地址 diff --git a/lab-60/lab-60-soul-spring-cloud-demo/pom.xml b/lab-60/lab-60-soul-spring-cloud-demo/pom.xml new file mode 100644 index 000000000..c512e70c5 --- /dev/null +++ b/lab-60/lab-60-soul-spring-cloud-demo/pom.xml @@ -0,0 +1,73 @@ + + + + lab-60 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60-soul-spring-cloud-demo + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + org.dromara + soul-client-springcloud + 2.1.2-RELEASE + + + + diff --git a/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/DemoApplication.java b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/DemoApplication.java new file mode 100644 index 000000000..6f4e8a3cf --- /dev/null +++ b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/DemoApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloud.lab60; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/controller/UserController.java b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/controller/UserController.java new file mode 100644 index 000000000..edb1623cf --- /dev/null +++ b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/controller/UserController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.lab60.controller; + +import cn.iocoder.springcloud.lab60.dto.UserCreateDTO; +import org.dromara.soul.client.common.annotation.SoulClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/user") +public class UserController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get") + @SoulClient(path = "/user/get", desc = "获得用户详细") + public String getUser(@RequestParam("id") Integer id) { + return "DEMO:" + id; + } + + @PostMapping("/create") + @SoulClient(path = "/user/create", desc = "创建用户") + public Integer createUser(@RequestBody UserCreateDTO createDTO) { + logger.info("[createUser][username({}) password({})]", createDTO.getNickname(), createDTO.getGender()); + return 1; + } + +} diff --git a/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/dto/UserCreateDTO.java b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/dto/UserCreateDTO.java new file mode 100644 index 000000000..99bff2223 --- /dev/null +++ b/lab-60/lab-60-soul-spring-cloud-demo/src/main/java/cn/iocoder/springcloud/lab60/dto/UserCreateDTO.java @@ -0,0 +1,34 @@ +package cn.iocoder.springcloud.lab60.dto; + +/** + * 用户创建 DTO + */ +public class UserCreateDTO { + + /** + * 昵称 + */ + private String nickname; + /** + * 性别 + */ + private Integer gender; + + public String getNickname() { + return nickname; + } + + public UserCreateDTO setNickname(String nickname) { + this.nickname = nickname; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserCreateDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/lab-60/lab-60-soul-spring-cloud-demo/src/main/resources/application.yaml b/lab-60/lab-60-soul-spring-cloud-demo/src/main/resources/application.yaml new file mode 100644 index 000000000..9b6941869 --- /dev/null +++ b/lab-60/lab-60-soul-spring-cloud-demo/src/main/resources/application.yaml @@ -0,0 +1,16 @@ +spring: + application: + name: sc-user-service # Spring 应用名 + cloud: + nacos: + # Nacos 作为注册中心的配置项,对应 NacosDiscoveryProperties 配置类 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +soul: + # Soul 针对 SpringMVC 的配置项,对应 SoulSpringCloudConfig 配置类 + springcloud: + admin-url: http://127.0.0.1:9095 # Soul Admin 地址 + context-path: /sc-user-service-api # 设置在 Soul 网关的路由前缀,例如说 /order、/product 等等。 + # 后续,网关会根据该 context-path 来进行路由 + app-name: sc-user-service # 应用名。未配置情况下,默认使用 `spring.application.name` 配置项 diff --git a/lab-60/pom.xml b/lab-60/pom.xml new file mode 100644 index 000000000..f7e815987 --- /dev/null +++ b/lab-60/pom.xml @@ -0,0 +1,21 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + lab-60 + pom + + + lab-60-soul-dubbo-demo + lab-60-soul-spring-boot-demo + lab-60-soul-spring-cloud-demo + + + diff --git "a/lab-60/\343\200\212\350\212\213\351\201\223 Soul \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" "b/lab-60/\343\200\212\350\212\213\351\201\223 Soul \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" new file mode 100644 index 000000000..7704af77e --- /dev/null +++ "b/lab-60/\343\200\212\350\212\213\351\201\223 Soul \346\236\201\347\256\200\345\205\245\351\227\250\357\274\210\345\233\275\344\272\247\345\276\256\346\234\215\345\212\241\347\275\221\345\205\263\357\274\211\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-provider/pom.xml b/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-provider/pom.xml index d34bd4dbc..b90611cc5 100644 --- a/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-provider/pom.xml +++ b/labx-07/labx-07-sca-dubbo-demo01/labx-07-sca-dubbo-demo01-provider/pom.xml @@ -20,9 +20,9 @@ + 引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。 + 在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系 + --> diff --git a/labx-07/labx-07-sca-dubbo-demo02/labx-07-sca-dubbo-demo02-provider-rest/pom.xml b/labx-07/labx-07-sca-dubbo-demo02/labx-07-sca-dubbo-demo02-provider-rest/pom.xml index ccff8b613..fcbc01ae6 100644 --- a/labx-07/labx-07-sca-dubbo-demo02/labx-07-sca-dubbo-demo02-provider-rest/pom.xml +++ b/labx-07/labx-07-sca-dubbo-demo02/labx-07-sca-dubbo-demo02-provider-rest/pom.xml @@ -21,9 +21,9 @@ + 引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。 + 在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系 + --> diff --git a/labx-08/labx-08-sc-gateway-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx08/gatewaydemo/GatewayApplication.java b/labx-08/labx-08-sc-gateway-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx08/gatewaydemo/GatewayApplication.java index 1ba74349f..1799fc890 100644 --- a/labx-08/labx-08-sc-gateway-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx08/gatewaydemo/GatewayApplication.java +++ b/labx-08/labx-08-sc-gateway-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx08/gatewaydemo/GatewayApplication.java @@ -1,5 +1,7 @@ package cn.iocoder.springcloud.labx08.gatewaydemo; +import com.alibaba.cloud.sentinel.gateway.ConfigConstants; +import com.alibaba.csp.sentinel.config.SentinelConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -7,8 +9,7 @@ public class GatewayApplication { public static void main(String[] args) { -// System.setProperty(SentinelConfig.APP_TYPE, ConfigConstants.APP_TYPE_SCG_GATEWAY); -// System.setProperty(SentinelConfig.APP_TYPE, "1"); + System.setProperty(SentinelConfig.APP_TYPE, ConfigConstants.APP_TYPE_SCG_GATEWAY); // 【重点】设置应用类型为 Spring Cloud Gateway SpringApplication.run(GatewayApplication.class, args); } diff --git a/labx-20/pom.xml b/labx-20/pom.xml index 77eafd34f..183ed2811 100644 --- a/labx-20/pom.xml +++ b/labx-20/pom.xml @@ -10,6 +10,7 @@ 4.0.0 labx-20 + pom labx-20-sca-bus-rocketmq-demo-publisher diff --git a/labx-21/labx-21-sc-user-service/pom.xml b/labx-21/labx-21-sc-user-service/pom.xml new file mode 100644 index 000000000..055cc5d76 --- /dev/null +++ b/labx-21/labx-21-sc-user-service/pom.xml @@ -0,0 +1,64 @@ + + + + labx-08 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-user-service + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + diff --git a/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/UserServiceApplication.java b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/UserServiceApplication.java new file mode 100644 index 000000000..a04578413 --- /dev/null +++ b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/UserServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloud.labx21.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/controller/UserController.java b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/controller/UserController.java new file mode 100644 index 000000000..4d340261d --- /dev/null +++ b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/controller/UserController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx21.userservice.controller; + +import cn.iocoder.springcloud.labx21.userservice.dto.UserAddDTO; +import cn.iocoder.springcloud.labx21.userservice.dto.UserDTO; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/user") +public class UserController { + + @GetMapping("/get") + public UserDTO get(@RequestParam("id") Integer id) { + return new UserDTO().setId(id) + .setName("没有昵称:" + id) + .setGender(id % 2 + 1); // 1 - 男;2 - 女 + } + + @PostMapping("/add") + public Integer add(UserAddDTO addDTO) { + return (int) (System.currentTimeMillis() / 1000); // 嘿嘿,随便返回一个 id + } + + @GetMapping("/sleep") + public void sleep() throws InterruptedException { + Thread.sleep(10 * 1000L); + } + +} diff --git a/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserAddDTO.java b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserAddDTO.java new file mode 100644 index 000000000..e4c2a2335 --- /dev/null +++ b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserAddDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.springcloud.labx21.userservice.dto; + +import java.io.Serializable; + +/** + * 用户添加 DTO + */ +public class UserAddDTO implements Serializable { + + /** + * 昵称 + */ + private String name; + /** + * 性别 + */ + private Integer gender; + + public String getName() { + return name; + } + + public UserAddDTO setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserAddDTO setGender(Integer gender) { + this.gender = gender; + return this; + } + +} diff --git a/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserDTO.java b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserDTO.java new file mode 100644 index 000000000..40184202e --- /dev/null +++ b/labx-21/labx-21-sc-user-service/src/main/java/cn/iocoder/springcloud/labx21/userservice/dto/UserDTO.java @@ -0,0 +1,49 @@ +package cn.iocoder.springcloud.labx21.userservice.dto; + +import java.io.Serializable; + +/** + * 用户信息 DTO + */ +public class UserDTO implements Serializable { + + /** + * 用户编号 + */ + private Integer id; + /** + * 昵称 + */ + private String name; + /** + * 性别 + */ + private Integer gender; + + public Integer getId() { + return id; + } + + public UserDTO setId(Integer id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public UserDTO setName(String name) { + this.name = name; + return this; + } + + public Integer getGender() { + return gender; + } + + public UserDTO setGender(Integer gender) { + this.gender = gender; + return this; + } +} diff --git a/labx-21/labx-21-sc-user-service/src/main/resources/application.yaml b/labx-21/labx-21-sc-user-service/src/main/resources/application.yaml new file mode 100644 index 000000000..ea9d953b1 --- /dev/null +++ b/labx-21/labx-21-sc-user-service/src/main/resources/application.yaml @@ -0,0 +1,12 @@ +spring: + application: + name: user-service # Spring 应用名 + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +server: + port: ${random.int[10000,19999]} # 服务器端口。默认为 8080 +# port: 18080 # 服务器端口。默认为 8080 diff --git a/labx-21/labx-21-sc-zuul-demo01/pom.xml b/labx-21/labx-21-sc-zuul-demo01/pom.xml new file mode 100644 index 000000000..08f84c8a3 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo01/pom.xml @@ -0,0 +1,58 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo01 + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + diff --git a/labx-21/labx-21-sc-zuul-demo01/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo01/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo01/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo01/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo01/src/main/resources/application.yaml new file mode 100644 index 000000000..6546e1b05 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo01/src/main/resources/application.yaml @@ -0,0 +1,18 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + route_yudaoyuanma: + path: /blog/** + url: http://www.iocoder.cn + route_oschina: + path: /oschina/** + url: https://www.oschina.net diff --git a/labx-21/labx-21-sc-zuul-demo02-registry/pom.xml b/labx-21/labx-21-sc-zuul-demo02-registry/pom.xml new file mode 100644 index 000000000..03afb6205 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo02-registry/pom.xml @@ -0,0 +1,64 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo02-registry + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + diff --git a/labx-21/labx-21-sc-zuul-demo02-registry/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo02-registry/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo02-registry/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo02-registry/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo02-registry/src/main/resources/application.yaml new file mode 100644 index 000000000..ce2d16ffe --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo02-registry/src/main/resources/application.yaml @@ -0,0 +1,27 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + route_yudaoyuanma: + path: /blog/** + url: http://www.iocoder.cn + route_oschina: + path: /oschina/** + url: https://www.oschina.net + route_users: + path: /users/** + service-id: user-service diff --git a/labx-21/labx-21-sc-zuul-demo03-config-apollo/pom.xml b/labx-21/labx-21-sc-zuul-demo03-config-apollo/pom.xml new file mode 100644 index 000000000..5560e84f5 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-apollo/pom.xml @@ -0,0 +1,73 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo03-config-apollo + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.ctrip.framework.apollo + apollo-client + 1.5.1 + + + + diff --git a/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulPropertiesRefresher.java b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulPropertiesRefresher.java new file mode 100644 index 000000000..558ebe84e --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulPropertiesRefresher.java @@ -0,0 +1,51 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent; +import org.springframework.cloud.netflix.zuul.filters.RouteLocator; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * 由 https://github.com/ctripcorp/apollo-use-cases/blob/master/spring-cloud-zuul 提供代码,感谢~ + */ +@Component +public class ZuulPropertiesRefresher { + + private static final Logger logger = LoggerFactory.getLogger(ZuulPropertiesRefresher.class); + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private RouteLocator routeLocator; + + @ApolloConfigChangeListener(interestedKeyPrefixes = "zuul.") + public void onChange(ConfigChangeEvent changeEvent) { + refreshZuulProperties(changeEvent); + } + + private void refreshZuulProperties(ConfigChangeEvent changeEvent) { + logger.info("Refreshing zuul properties!"); + + /* + * rebind configuration beans, e.g. ZuulProperties + * @see org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent + */ + this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys())); + + /* + * refresh routes + * @see org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration.ZuulRefreshListener#onApplicationEvent + */ + this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator)); + + logger.info("Zuul properties refreshed!"); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/resources/application.yaml new file mode 100644 index 000000000..871cb3e5d --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-apollo/src/main/resources/application.yaml @@ -0,0 +1,23 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +# Apollo 相关配置项 +app: + id: ${spring.application.name} # 使用的 Apollo 的项目(应用)编号 +apollo: + meta: http://127.0.0.1:8080 # Apollo Meta Server 地址 + bootstrap: + enabled: true # 是否开启 Apollo 配置预加载功能。默认为 false。 + eagerLoad: + enable: true # 是否开启 Apollo 支持日志级别的加载时机。默认为 false。 + namespaces: application # 使用的 Apollo 的命名空间,默认为 application。 diff --git a/labx-21/labx-21-sc-zuul-demo03-config-nacos/pom.xml b/labx-21/labx-21-sc-zuul-demo03-config-nacos/pom.xml new file mode 100644 index 000000000..052cf9edd --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-nacos/pom.xml @@ -0,0 +1,72 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo03-config-nacos + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + diff --git a/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulRouteRefreshListener.java b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulRouteRefreshListener.java new file mode 100644 index 000000000..9e65cf0d7 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulRouteRefreshListener.java @@ -0,0 +1,43 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent; +import org.springframework.cloud.netflix.zuul.filters.RouteLocator; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +@Component +public class ZuulRouteRefreshListener implements ApplicationListener { + + private static final Logger logger = LoggerFactory.getLogger(ZuulRouteRefreshListener.class); + + @Autowired + private ApplicationEventPublisher publisher; + + @Autowired + private RouteLocator routeLocator; + + @Override + public void onApplicationEvent(EnvironmentChangeEvent event) { + // 判断是否有 `zuul.` 配置变化 + boolean zuulConfigUpdated = false; + for (String key : event.getKeys()) { + if (key.startsWith("zuul.")) { + zuulConfigUpdated = true; + break; + } + } + if (!zuulConfigUpdated) { + return; + } + + // 发布 RoutesRefreshedEvent 事件 + this.publisher.publishEvent(new RoutesRefreshedEvent(routeLocator)); + logger.info("发布 RoutesRefreshedEvent 事件完成,刷新 Zuul 路由"); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/application.yaml new file mode 100644 index 000000000..f2bc95d7e --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/application.yaml @@ -0,0 +1,9 @@ +server: + port: 8888 + +spring: + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 diff --git a/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/bootstrap.yaml b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/bootstrap.yaml new file mode 100644 index 000000000..b945dd27d --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo03-config-nacos/src/main/resources/bootstrap.yaml @@ -0,0 +1,13 @@ +spring: + application: + name: zuul-application + + cloud: + nacos: + # Nacos Config 配置项,对应 NacosConfigProperties 配置属性类 + config: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + namespace: # 使用的 Nacos 的命名空间,默认为 null + group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP + name: # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name + file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties diff --git a/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/pom.xml b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/pom.xml new file mode 100644 index 000000000..e16ab482a --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/pom.xml @@ -0,0 +1,58 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo05-custom-zuul-filter + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + diff --git a/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/filter/AuthZuulFilter.java b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/filter/AuthZuulFilter.java new file mode 100644 index 000000000..1013b926e --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/filter/AuthZuulFilter.java @@ -0,0 +1,75 @@ +package cn.iocoder.springcloud.labx21.zuuldemo.filter; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +@Component +public class AuthZuulFilter extends ZuulFilter { + + /** + * 外部请求 Header - token 认证令牌 + */ + private static final String DEFAULT_TOKEN_HEADER_NAME = "token"; + /** + * 转发请求 Header - userId 用户编号 + */ + private static final String DEFAULT_HEADER_NAME = "user-id"; + + /** + * token 和 userId 的映射 + */ + private static Map TOKENS = new HashMap(); + + static { + TOKENS.put("yunai", 1); + } + + public String filterType() { + return FilterConstants.PRE_TYPE; // 前置过滤器 + } + + public int filterOrder() { + return 0; + } + + public boolean shouldFilter() { + return true; // 需要过滤 + } + + public Object run() throws ZuulException { + // 获取当前请求上下文 + RequestContext ctx = RequestContext.getCurrentContext(); + // 获得 token + HttpServletRequest request = ctx.getRequest(); + String token = request.getHeader(DEFAULT_TOKEN_HEADER_NAME); + + // 如果没有 token,则不进行认证。因为可能是无需认证的 API 接口 + if (!StringUtils.hasText(token)) { + return null; + } + + // 进行认证 + Integer userId = TOKENS.get(token); + + // 通过 token 获取不到 userId,说明认证不通过 + if (userId == null) { + ctx.setSendZuulResponse(false); + ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); // 响应 401 状态码 + return null; + } + + // 认证通过,将 userId 添加到 Header 中 + ctx.getZuulRequestHeaders().put(DEFAULT_HEADER_NAME, String.valueOf(userId)); + return null; + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/resources/application.yaml new file mode 100644 index 000000000..6546e1b05 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo05-custom-zuul-filter/src/main/resources/application.yaml @@ -0,0 +1,18 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + route_yudaoyuanma: + path: /blog/** + url: http://www.iocoder.cn + route_oschina: + path: /oschina/** + url: https://www.oschina.net diff --git a/labx-21/labx-21-sc-zuul-demo07-hystrix/pom.xml b/labx-21/labx-21-sc-zuul-demo07-hystrix/pom.xml new file mode 100644 index 000000000..7edd7ff61 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-hystrix/pom.xml @@ -0,0 +1,64 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo07-hystrix + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + diff --git a/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/fallback/ApiFallbackProvider.java b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/fallback/ApiFallbackProvider.java new file mode 100644 index 000000000..9da8b5505 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/fallback/ApiFallbackProvider.java @@ -0,0 +1,51 @@ +package cn.iocoder.springcloud.labx21.zuuldemo.fallback; + +import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +@Component +public class ApiFallbackProvider implements FallbackProvider { + + public String getRoute() { + return "*"; + } + + public ClientHttpResponse fallbackResponse(String route, final Throwable cause) { + return new ClientHttpResponse() { + + public HttpStatus getStatusCode() { + return HttpStatus.OK; + } + + public int getRawStatusCode() { + return HttpStatus.OK.value(); + } + + public String getStatusText() { + return HttpStatus.OK.getReasonPhrase(); + } + + public void close() {} + + public InputStream getBody() { // 响应内容 + String bodyText = String.format("{\"code\": 500,\"message\": \"Service unavailable:%s\"}", cause.getMessage()); + return new ByteArrayInputStream(bodyText.getBytes()); + } + + public HttpHeaders getHeaders() { // 响应头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); // json 返回 + return headers; + } + + }; + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/resources/application.yaml new file mode 100644 index 000000000..ce2d16ffe --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-hystrix/src/main/resources/application.yaml @@ -0,0 +1,27 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + route_yudaoyuanma: + path: /blog/** + url: http://www.iocoder.cn + route_oschina: + path: /oschina/** + url: https://www.oschina.net + route_users: + path: /users/** + service-id: user-service diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/pom.xml b/labx-21/labx-21-sc-zuul-demo07-sentinel/pom.xml new file mode 100644 index 000000000..1b04cf316 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/pom.xml @@ -0,0 +1,68 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo07-sentinel + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + com.alibaba.cloud + spring-cloud-alibaba-sentinel-gateway + + + + diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/CustomBlockFallbackProvider.java b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/CustomBlockFallbackProvider.java new file mode 100644 index 000000000..2a7285ee9 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/CustomBlockFallbackProvider.java @@ -0,0 +1,31 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager; +import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class CustomBlockFallbackProvider implements ZuulBlockFallbackProvider { + + @PostConstruct + public void init() { + ZuulBlockFallbackManager.registerProvider(this); // 注册到 ZuulBlockFallbackManager + } + + public String getRoute() { + return "*"; + } + + public BlockResponse fallbackResponse(String route, Throwable cause) { + if (cause instanceof BlockException) { + return new BlockResponse(429, "你被 Block 啦!", route); + } else { + return new BlockResponse(500, "系统异常", route); + } + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..99e4ff63b --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,18 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import com.alibaba.cloud.sentinel.gateway.ConfigConstants; +import com.alibaba.csp.sentinel.config.SentinelConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + System.setProperty(SentinelConfig.APP_TYPE, ConfigConstants.APP_TYPE_ZUUL_GATEWAY); // 【重点】设置应用类型为 Zuul + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/application.yaml new file mode 100644 index 000000000..13080f5c3 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/application.yaml @@ -0,0 +1,42 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + + cloud: + nacos: + # Nacos 作为注册中心的配置项 + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + + sentinel: + eager: true # 是否饥饿加载。默认为 false 关闭 + transport: + dashboard: localhost:7070 # 是否饥饿加载。 + # # 数据源的配置项 + # datasource: + # ds1.file: + # file: "classpath: sentinel-gw-flow.json" + # ruleType: gw-flow + # ds2.file: + # file: "classpath: sentinel-gw-api-group.json" + # ruleType: gw-api-group + # Sentinel 对 Zuul 的专属配置项,对应 SentinelZuulProperties 类 + zuul: + order: + pre: 10000 # 前置过滤器 SentinelZuulPreFilter 的顺序 + post: 1000 # 后置过滤器 SentinelZuulPostFilter 的顺序 + error: -1 # 错误过滤器 SentinelZuulErrorFilter 的顺序 + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + yudaoyuanma: # 这是一个 Route 编号 + path: /** + url: http://www.iocoder.cn + + diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-api-group.json b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-api-group.json new file mode 100644 index 000000000..0e47591bc --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-api-group.json @@ -0,0 +1,23 @@ +[ + { + "apiName": "yudaoyuanma_customized_api", + "predicateItems": [ + { + "pattern": "/categories/**", + "matchStrategy": 1 + }, + { + "items": [ + { + "pattern": "/Dubbo/good-collection/", + "matchStrategy": 0 + }, + { + "pattern": "/SkyWalking/**", + "matchStrategy": 1 + } + ] + } + ] + } +] diff --git a/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-flow.json b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-flow.json new file mode 100644 index 000000000..8a53df34c --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo07-sentinel/src/main/resources/sentinel-gw-flow.json @@ -0,0 +1,10 @@ +[ + { + "resource": "yudaoyuanma", + "count": 3 + }, + { + "resource": "yudaoyuanma_customized_api", + "count": 1 + } +] diff --git a/labx-21/labx-21-sc-zuul-demo09-actuator/pom.xml b/labx-21/labx-21-sc-zuul-demo09-actuator/pom.xml new file mode 100644 index 000000000..a2ae16fae --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo09-actuator/pom.xml @@ -0,0 +1,58 @@ + + + + labx-21 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21-sc-zuul-demo09-actuator + + + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + + diff --git a/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java b/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java new file mode 100644 index 000000000..e9f0fce24 --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/java/cn/iocoder/springcloud/labx21/zuuldemo/ZuulApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx21.zuuldemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +@SpringBootApplication +@EnableZuulProxy // 开启 Zuul 网关 +public class ZuulApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulApplication.class, args); + } + +} diff --git a/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/resources/application.yaml b/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/resources/application.yaml new file mode 100644 index 000000000..d4a4ce03c --- /dev/null +++ b/labx-21/labx-21-sc-zuul-demo09-actuator/src/main/resources/application.yaml @@ -0,0 +1,31 @@ +server: + port: 8888 + +spring: + application: + name: zuul-application + +# Zuul 配置项,对应 ZuulProperties 配置类 +zuul: + servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul + # 路由配置项,对应 ZuulRoute Map + routes: + route_yudaoyuanma: + path: /blog/** + url: http://www.iocoder.cn + route_oschina: + path: /oschina/** + url: https://www.oschina.net + +management: + endpoints: + web: + exposure: + include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + endpoint: + # Health 端点配置项,对应 HealthProperties 配置类 + health: + enabled: true # 是否开启。默认为 true 开启。 + show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。 + server: + port: 18888 # 单独设置端口,因为 8888 端口全部给 Zuul 了 diff --git a/labx-21/pom.xml b/labx-21/pom.xml new file mode 100644 index 000000000..8047a7156 --- /dev/null +++ b/labx-21/pom.xml @@ -0,0 +1,28 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-21 + pom + + labx-21-sc-zuul-demo01 + labx-21-sc-zuul-demo02-registry + labx-21-sc-zuul-demo03-config-apollo + labx-21-sc-zuul-demo03-config-nacos + labx-21-sc-zuul-demo05-custom-zuul-filter + labx-21-sc-zuul-demo07-hystrix + labx-21-sc-zuul-demo07-sentinel + labx-21-sc-zuul-demo09-actuator + + labx-21-sc-user-service + + + + diff --git "a/labx-21/\343\200\212\350\212\213\351\201\223 Spring Cloud \347\275\221\345\205\263 Zuul \345\205\245\351\227\250\343\200\213.md" "b/labx-21/\343\200\212\350\212\213\351\201\223 Spring Cloud \347\275\221\345\205\263 Zuul \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..6066f383c --- /dev/null +++ "b/labx-21/\343\200\212\350\212\213\351\201\223 Spring Cloud \347\275\221\345\205\263 Zuul \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/labx-22/labx-22-scn-eureka-demo01-consumer/pom.xml b/labx-22/labx-22-scn-eureka-demo01-consumer/pom.xml new file mode 100644 index 000000000..53c76cc8c --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-consumer/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo01-consumer + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java b/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java new file mode 100644 index 000000000..93f81a069 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java @@ -0,0 +1,69 @@ +package cn.iocoder.springcloudalibaba.labx22.consumerdemo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +@SpringBootApplication +// @EnableDiscoveryClient +public class DemoConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoConsumerApplication.class, args); + } + + @Configuration + public class RestTemplateConfiguration { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + } + + @RestController + static class TestController { + + @Autowired + private DiscoveryClient discoveryClient; + @Autowired + private RestTemplate restTemplate; + @Autowired + private LoadBalancerClient loadBalancerClient; + + @GetMapping("/hello") + public String hello(String name) { + // 获得服务 `demo-provider` 的一个实例 + ServiceInstance instance; + if (true) { + // 获取服务 `demo-provider` 对应的实例列表 + List instances = discoveryClient.getInstances("demo-provider"); + // 选择第一个 + instance = instances.size() > 0 ? instances.get(0) : null; + } else { + instance = loadBalancerClient.choose("demo-provider"); + } + // 发起调用 + if (instance == null) { + throw new IllegalStateException("获取不到实例"); + } + String targetUrl = instance.getUri() + "/echo?name=" + name; + String response = restTemplate.getForObject(targetUrl, String.class); + // 返回结果 + return "consumer:" + response; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/resources/application.yaml new file mode 100644 index 000000000..e14a07c8b --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-consumer/src/main/resources/application.yaml @@ -0,0 +1,12 @@ +spring: + application: + name: demo-consumer # Spring 应用名 +server: + port: 28080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true + fetch-registry: true + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ diff --git a/labx-22/labx-22-scn-eureka-demo01-provider/pom.xml b/labx-22/labx-22-scn-eureka-demo01-provider/pom.xml new file mode 100644 index 000000000..52f5d98f3 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-provider/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo01-provider + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java b/labx-22/labx-22-scn-eureka-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java new file mode 100644 index 000000000..aed296861 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java @@ -0,0 +1,27 @@ +package cn.iocoder.springcloudalibaba.labx22.providerdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +@EnableDiscoveryClient +public class DemoProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoProviderApplication.class, args); + } + + @RestController + static class TestController { + + @GetMapping("/echo") + public String echo(String name) { + return "provider:" + name; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo01-provider/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo01-provider/src/main/resources/application.yaml new file mode 100644 index 000000000..2bfb44e62 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo01-provider/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +spring: + application: + name: demo-provider # Spring 应用名 + +server: + port: 18080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true # 注册到 Eureka-Server,默认为 true + fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址 diff --git a/labx-22/labx-22-scn-eureka-demo02-consumer/pom.xml b/labx-22/labx-22-scn-eureka-demo02-consumer/pom.xml new file mode 100644 index 000000000..51fd23691 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-consumer/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo02-consumer + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java b/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java new file mode 100644 index 000000000..93f81a069 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java @@ -0,0 +1,69 @@ +package cn.iocoder.springcloudalibaba.labx22.consumerdemo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +@SpringBootApplication +// @EnableDiscoveryClient +public class DemoConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoConsumerApplication.class, args); + } + + @Configuration + public class RestTemplateConfiguration { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + } + + @RestController + static class TestController { + + @Autowired + private DiscoveryClient discoveryClient; + @Autowired + private RestTemplate restTemplate; + @Autowired + private LoadBalancerClient loadBalancerClient; + + @GetMapping("/hello") + public String hello(String name) { + // 获得服务 `demo-provider` 的一个实例 + ServiceInstance instance; + if (true) { + // 获取服务 `demo-provider` 对应的实例列表 + List instances = discoveryClient.getInstances("demo-provider"); + // 选择第一个 + instance = instances.size() > 0 ? instances.get(0) : null; + } else { + instance = loadBalancerClient.choose("demo-provider"); + } + // 发起调用 + if (instance == null) { + throw new IllegalStateException("获取不到实例"); + } + String targetUrl = instance.getUri() + "/echo?name=" + name; + String response = restTemplate.getForObject(targetUrl, String.class); + // 返回结果 + return "consumer:" + response; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/resources/application.yaml new file mode 100644 index 000000000..287327529 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-consumer/src/main/resources/application.yaml @@ -0,0 +1,12 @@ +spring: + application: + name: demo-consumer # Spring 应用名 +server: + port: 28080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true # 注册到 Eureka-Server,默认为 true + fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true + service-url: + defaultZone: http://eureka-node01:18761/eureka/, http://eureka-node02:28761/eureka/ diff --git a/labx-22/labx-22-scn-eureka-demo02-provider/pom.xml b/labx-22/labx-22-scn-eureka-demo02-provider/pom.xml new file mode 100644 index 000000000..689ba14f3 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-provider/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo02-provider + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo02-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java b/labx-22/labx-22-scn-eureka-demo02-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java new file mode 100644 index 000000000..aed296861 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java @@ -0,0 +1,27 @@ +package cn.iocoder.springcloudalibaba.labx22.providerdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +@EnableDiscoveryClient +public class DemoProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoProviderApplication.class, args); + } + + @RestController + static class TestController { + + @GetMapping("/echo") + public String echo(String name) { + return "provider:" + name; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo02-provider/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo02-provider/src/main/resources/application.yaml new file mode 100644 index 000000000..5e5592e07 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo02-provider/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +spring: + application: + name: demo-provider # Spring 应用名 + +server: + port: 18080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true # 注册到 Eureka-Server,默认为 true + fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true + service-url: + defaultZone: http://eureka-node01:18761/eureka/, http://eureka-node02:28761/eureka/ diff --git a/labx-22/labx-22-scn-eureka-demo03-consumer/pom.xml b/labx-22/labx-22-scn-eureka-demo03-consumer/pom.xml new file mode 100644 index 000000000..ab52e0025 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-consumer/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo03-consumer + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java b/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java new file mode 100644 index 000000000..93f81a069 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/java/cn/iocoder/springcloudalibaba/labx22/consumerdemo/DemoConsumerApplication.java @@ -0,0 +1,69 @@ +package cn.iocoder.springcloudalibaba.labx22.consumerdemo; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +@SpringBootApplication +// @EnableDiscoveryClient +public class DemoConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoConsumerApplication.class, args); + } + + @Configuration + public class RestTemplateConfiguration { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + } + + @RestController + static class TestController { + + @Autowired + private DiscoveryClient discoveryClient; + @Autowired + private RestTemplate restTemplate; + @Autowired + private LoadBalancerClient loadBalancerClient; + + @GetMapping("/hello") + public String hello(String name) { + // 获得服务 `demo-provider` 的一个实例 + ServiceInstance instance; + if (true) { + // 获取服务 `demo-provider` 对应的实例列表 + List instances = discoveryClient.getInstances("demo-provider"); + // 选择第一个 + instance = instances.size() > 0 ? instances.get(0) : null; + } else { + instance = loadBalancerClient.choose("demo-provider"); + } + // 发起调用 + if (instance == null) { + throw new IllegalStateException("获取不到实例"); + } + String targetUrl = instance.getUri() + "/echo?name=" + name; + String response = restTemplate.getForObject(targetUrl, String.class); + // 返回结果 + return "consumer:" + response; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/resources/application.yaml new file mode 100644 index 000000000..5efb19a92 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-consumer/src/main/resources/application.yaml @@ -0,0 +1,12 @@ +spring: + application: + name: demo-consumer # Spring 应用名 +server: + port: 28080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true + fetch-registry: true + service-url: + defaultZone: http://eureka:woshimima@127.0.0.1:8761/eureka/ # Eureka-Server 地址 diff --git a/labx-22/labx-22-scn-eureka-demo03-provider/pom.xml b/labx-22/labx-22-scn-eureka-demo03-provider/pom.xml new file mode 100644 index 000000000..2cadeb4a1 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-provider/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-demo03-provider + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-22/labx-22-scn-eureka-demo03-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java b/labx-22/labx-22-scn-eureka-demo03-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java new file mode 100644 index 000000000..aed296861 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-provider/src/main/java/cn/iocoder/springcloudalibaba/labx22/providerdemo/DemoProviderApplication.java @@ -0,0 +1,27 @@ +package cn.iocoder.springcloudalibaba.labx22.providerdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +@EnableDiscoveryClient +public class DemoProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoProviderApplication.class, args); + } + + @RestController + static class TestController { + + @GetMapping("/echo") + public String echo(String name) { + return "provider:" + name; + } + + } + +} diff --git a/labx-22/labx-22-scn-eureka-demo03-provider/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-demo03-provider/src/main/resources/application.yaml new file mode 100644 index 000000000..5cd1772d4 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-demo03-provider/src/main/resources/application.yaml @@ -0,0 +1,13 @@ +spring: + application: + name: demo-provider # Spring 应用名 + +server: + port: 18080 # 服务器端口。默认为 8080 + +eureka: + client: + register-with-eureka: true # 注册到 Eureka-Server,默认为 true + fetch-registry: true # 从 Eureka-Server 获取注册表,默认为 true + service-url: + defaultZone: http://eureka:woshimima@127.0.0.1:8761/eureka/ # Eureka-Server 地址 diff --git a/labx-22/labx-22-scn-eureka-server-cluster/pom.xml b/labx-22/labx-22-scn-eureka-server-cluster/pom.xml new file mode 100644 index 000000000..722dc56a2 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-cluster/pom.xml @@ -0,0 +1,50 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-server-cluster + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + diff --git a/labx-22/labx-22-scn-eureka-server-cluster/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java b/labx-22/labx-22-scn-eureka-server-cluster/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java new file mode 100644 index 000000000..22986a7bd --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-cluster/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloudalibaba.labx22.eurekaserverdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaServerApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaServerApplication.class,args); + } + +} diff --git a/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node01.yaml b/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node01.yaml new file mode 100644 index 000000000..3207162a6 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node01.yaml @@ -0,0 +1,15 @@ +server: + port: 18761 + +spring: + application: + name: eureka-server + +eureka: + instance: + hostname: eureka-node01 + client: + register-with-eureka: true + fetch-registry: true + service-url: + defaultZone: http://eureka-node02:28761/eureka/ diff --git a/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node02.yaml b/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node02.yaml new file mode 100644 index 000000000..1c44ec485 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-cluster/src/main/resources/application-node02.yaml @@ -0,0 +1,15 @@ +server: + port: 28761 + +spring: + application: + name: eureka-server + +eureka: + instance: + hostname: eureka-node02 + client: + register-with-eureka: true + fetch-registry: true + service-url: + defaultZone: http://eureka-node01:18761/eureka/ diff --git a/labx-22/labx-22-scn-eureka-server-security/pom.xml b/labx-22/labx-22-scn-eureka-server-security/pom.xml new file mode 100644 index 000000000..4a8ec5149 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-security/pom.xml @@ -0,0 +1,56 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-server-security + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + + org.springframework.boot + spring-boot-starter-security + + + + diff --git a/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java b/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java new file mode 100644 index 000000000..22986a7bd --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloudalibaba.labx22.eurekaserverdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaServerApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaServerApplication.class,args); + } + +} diff --git a/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/config/WebSecurityConfig.java b/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/config/WebSecurityConfig.java new file mode 100644 index 000000000..56fe05daa --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-security/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/config/WebSecurityConfig.java @@ -0,0 +1,16 @@ +package cn.iocoder.springcloudalibaba.labx22.eurekaserverdemo.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().ignoringAntMatchers("/eureka/**"); + super.configure(http); + } + +} diff --git a/labx-22/labx-22-scn-eureka-server-security/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-server-security/src/main/resources/application.yaml new file mode 100644 index 000000000..ef1eeb8b2 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-security/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +server: + port: 8761 # 设置 Eureka-Server 的端口 + +spring: + application: + name: eureka-server + + # 使用 Spring Security 创建默认认证账号 + security: + user: + name: eureka + password: woshimima + +eureka: + client: + register-with-eureka: false # 不注册到 Eureka-Server,默认为 true + fetch-registry: false # 不从 Eureka-Server 获取注册表,默认为 true diff --git a/labx-22/labx-22-scn-eureka-server-standalone/pom.xml b/labx-22/labx-22-scn-eureka-server-standalone/pom.xml new file mode 100644 index 000000000..872e458e9 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-standalone/pom.xml @@ -0,0 +1,50 @@ + + + + labx-22 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22-scn-eureka-server-standalone + + + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + + diff --git a/labx-22/labx-22-scn-eureka-server-standalone/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java b/labx-22/labx-22-scn-eureka-server-standalone/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java new file mode 100644 index 000000000..22986a7bd --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-standalone/src/main/java/cn/iocoder/springcloudalibaba/labx22/eurekaserverdemo/EurekaServerApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloudalibaba.labx22.eurekaserverdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaServerApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaServerApplication.class,args); + } + +} diff --git a/labx-22/labx-22-scn-eureka-server-standalone/src/main/resources/application.yaml b/labx-22/labx-22-scn-eureka-server-standalone/src/main/resources/application.yaml new file mode 100644 index 000000000..341905524 --- /dev/null +++ b/labx-22/labx-22-scn-eureka-server-standalone/src/main/resources/application.yaml @@ -0,0 +1,11 @@ +server: + port: 8761 # 设置 Eureka-Server 的端口 + +spring: + application: + name: eureka-server + +eureka: + client: + register-with-eureka: false # 不注册到 Eureka-Server,默认为 true + fetch-registry: false # 不从 Eureka-Server 获取注册表,默认为 true diff --git a/labx-22/pom.xml b/labx-22/pom.xml new file mode 100644 index 000000000..2208a843e --- /dev/null +++ b/labx-22/pom.xml @@ -0,0 +1,29 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-22 + pom + + labx-22-scn-eureka-server-standalone + labx-22-scn-eureka-demo01-provider + labx-22-scn-eureka-demo01-consumer + + labx-22-scn-eureka-server-cluster + labx-22-scn-eureka-demo02-provider + labx-22-scn-eureka-demo02-consumer + + labx-22-scn-eureka-server-security + labx-22-scn-eureka-demo03-provider + labx-22-scn-eureka-demo03-consumer + + + + diff --git "a/labx-22/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\263\250\345\206\214\344\270\255\345\277\203 Eureka \345\205\245\351\227\250\343\200\213.md" "b/labx-22/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\263\250\345\206\214\344\270\255\345\277\203 Eureka \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..9dec8cc5a --- /dev/null +++ "b/labx-22/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\263\250\345\206\214\344\270\255\345\277\203 Eureka \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/labx-23/labx-23-scn-hystrix-actuator/pom.xml b/labx-23/labx-23-scn-hystrix-actuator/pom.xml new file mode 100644 index 000000000..ec5de6add --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/pom.xml @@ -0,0 +1,64 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-actuator + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java new file mode 100644 index 000000000..5620feaa0 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java @@ -0,0 +1,22 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableCircuitBreaker // 声明开启断路器 +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java new file mode 100644 index 000000000..8af86c48c --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java @@ -0,0 +1,33 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CacheDemoService; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +@RequestMapping("/cache-demo") +public class CacheDemoController { + + @Autowired + private CacheDemoService cacheDemoService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + String userB = cacheDemoService.getUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + + @GetMapping("/update_user") + public String updateUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + cacheDemoService.updateUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java new file mode 100644 index 000000000..df3bac8ae --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java @@ -0,0 +1,46 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CollapserDemoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +@RestController +@RequestMapping("/collapser-demo") +public class CollapserDemoController { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoController.class); + + @Autowired + private CollapserDemoService collapserDemoService; + + @GetMapping("/test") + public void test() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(1); + Future user02 = collapserDemoService.getUserFuture(2); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + + + @GetMapping("/test_02") + public void test02() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(2); + Future user02 = collapserDemoService.getUserFuture(1); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java new file mode 100644 index 000000000..47db0bf24 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java new file mode 100644 index 000000000..99b732608 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.filter; + +import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +@Component +@WebFilter(urlPatterns = "/") +public class HystrixRequestContextFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + // 初始化 HystrixRequestContext + HystrixRequestContext context = HystrixRequestContext.initializeContext(); + // 继续过滤器 + try { + chain.doFilter(request, response); + } finally { + // 销毁 HystrixRequestContext + context.close(); + } + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java new file mode 100644 index 000000000..0241062d6 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java @@ -0,0 +1,43 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class CacheDemoService { + + private Logger logger = LoggerFactory.getLogger(CacheDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCommand(fallbackMethod = "getUserFallback") + @CacheResult(cacheKeyMethod = "genGetUserCacheKey") + public String getUser(Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + @HystrixCommand + @CacheRemove(commandKey = "getUser", cacheKeyMethod = "genGetUserCacheKey") + public void updateUser(Integer id) { + logger.info("[updateUser][更新用户({})详情]", id); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + + public String genGetUserCacheKey(Integer id) { + return "USER_" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java new file mode 100644 index 000000000..4006bd492 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java @@ -0,0 +1,44 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + +@Service +public class CollapserDemoService { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCollapser( + batchMethod = "getUsers", + collapserProperties = { + @HystrixProperty(name = "timerDelayInMilliseconds", value = "10000") // 演示,所以设置的时间较长 + } + ) + public Future getUserFuture(Integer id) { + throw new RuntimeException("This method body should not be executed"); + } + + @HystrixCommand + public List getUsers(List ids) { + logger.info("[getUsers][准备调用 user-service 获取多个用户({})详情]", ids); + String[] users = restTemplate.getForEntity("http://127.0.0.1:18080/user/batch_get?ids=" + StringUtils.join(ids, ',') + , String[].class).getBody(); + return users == null || users.length == 0 ? Collections.emptyList() : Arrays.asList(users); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-actuator/src/main/resources/application.yml b/labx-23/labx-23-scn-hystrix-actuator/src/main/resources/application.yml new file mode 100644 index 000000000..75c2d1ee9 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-actuator/src/main/resources/application.yml @@ -0,0 +1,5 @@ +management: + endpoints: + web: + exposure: + include: 'hystrix.stream' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 diff --git a/labx-23/labx-23-scn-hystrix-dashboard-turbine/pom.xml b/labx-23/labx-23-scn-hystrix-dashboard-turbine/pom.xml new file mode 100644 index 000000000..2a240d813 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard-turbine/pom.xml @@ -0,0 +1,70 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dashboard-turbine + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix-dashboard + + + + + org.springframework.cloud + spring-cloud-starter-netflix-turbine + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java b/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java new file mode 100644 index 000000000..ae18d6f4f --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java @@ -0,0 +1,17 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; +import org.springframework.cloud.netflix.turbine.EnableTurbine; + +@SpringBootApplication +@EnableHystrixDashboard // 声明开启 Hystrix Dashboard 功能 +@EnableTurbine // 声明开启 Turbine 功能 +public class HystrixDashboardApplication { + + public static void main(String[] args) { + SpringApplication.run(HystrixDashboardApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/resources/application.yml b/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/resources/application.yml new file mode 100644 index 000000000..f0c510b16 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/resources/application.yml @@ -0,0 +1,17 @@ +server: + port: 9090 + +spring: + application: + name: hystrix-dashboard + +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址 + +# Turbine 配置项,对应 TurbineProperties 配置类 +turbine: + app-config: hystrix-demo # 配置需要 Turbine 聚合的服务名;如果有多个,使用逗号分隔。 + combine-host-port: true # 服务是否以 host + port 进行区分,默认为 true。如果设置为 false,则只以 host 进行区分,这样会导致相同主机部署了相同服务的多个实例,会被认为是一个 + cluster-name-expression: new String('default') # 指定集群名,设置为 `default` 表示默认集群。 diff --git a/labx-23/labx-23-scn-hystrix-dashboard/pom.xml b/labx-23/labx-23-scn-hystrix-dashboard/pom.xml new file mode 100644 index 000000000..a7104d3c8 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard/pom.xml @@ -0,0 +1,58 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dashboard + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix-dashboard + + + + diff --git a/labx-23/labx-23-scn-hystrix-dashboard/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java b/labx-23/labx-23-scn-hystrix-dashboard/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java new file mode 100644 index 000000000..b010fe819 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/HystrixDashboardApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; + +@SpringBootApplication +@EnableHystrixDashboard // 声明开启 Hystrix Dashboard 功能 +public class HystrixDashboardApplication { + + public static void main(String[] args) { + SpringApplication.run(HystrixDashboardApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dashboard/src/main/resources/application.yml b/labx-23/labx-23-scn-hystrix-dashboard/src/main/resources/application.yml new file mode 100644 index 000000000..f9e9468c1 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dashboard/src/main/resources/application.yml @@ -0,0 +1,2 @@ +server: + port: 9090 diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/pom.xml b/labx-23/labx-23-scn-hystrix-demo01-cluster/pom.xml new file mode 100644 index 000000000..f2b08653d --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/pom.xml @@ -0,0 +1,70 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-demo01-cluster + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + + diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java new file mode 100644 index 000000000..5620feaa0 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java @@ -0,0 +1,22 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableCircuitBreaker // 声明开启断路器 +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java new file mode 100644 index 000000000..8af86c48c --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java @@ -0,0 +1,33 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CacheDemoService; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +@RequestMapping("/cache-demo") +public class CacheDemoController { + + @Autowired + private CacheDemoService cacheDemoService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + String userB = cacheDemoService.getUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + + @GetMapping("/update_user") + public String updateUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + cacheDemoService.updateUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java new file mode 100644 index 000000000..df3bac8ae --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java @@ -0,0 +1,46 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CollapserDemoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +@RestController +@RequestMapping("/collapser-demo") +public class CollapserDemoController { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoController.class); + + @Autowired + private CollapserDemoService collapserDemoService; + + @GetMapping("/test") + public void test() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(1); + Future user02 = collapserDemoService.getUserFuture(2); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + + + @GetMapping("/test_02") + public void test02() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(2); + Future user02 = collapserDemoService.getUserFuture(1); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java new file mode 100644 index 000000000..47db0bf24 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java new file mode 100644 index 000000000..99b732608 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.filter; + +import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +@Component +@WebFilter(urlPatterns = "/") +public class HystrixRequestContextFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + // 初始化 HystrixRequestContext + HystrixRequestContext context = HystrixRequestContext.initializeContext(); + // 继续过滤器 + try { + chain.doFilter(request, response); + } finally { + // 销毁 HystrixRequestContext + context.close(); + } + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java new file mode 100644 index 000000000..0241062d6 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java @@ -0,0 +1,43 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class CacheDemoService { + + private Logger logger = LoggerFactory.getLogger(CacheDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCommand(fallbackMethod = "getUserFallback") + @CacheResult(cacheKeyMethod = "genGetUserCacheKey") + public String getUser(Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + @HystrixCommand + @CacheRemove(commandKey = "getUser", cacheKeyMethod = "genGetUserCacheKey") + public void updateUser(Integer id) { + logger.info("[updateUser][更新用户({})详情]", id); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + + public String genGetUserCacheKey(Integer id) { + return "USER_" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java new file mode 100644 index 000000000..4006bd492 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java @@ -0,0 +1,44 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + +@Service +public class CollapserDemoService { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCollapser( + batchMethod = "getUsers", + collapserProperties = { + @HystrixProperty(name = "timerDelayInMilliseconds", value = "10000") // 演示,所以设置的时间较长 + } + ) + public Future getUserFuture(Integer id) { + throw new RuntimeException("This method body should not be executed"); + } + + @HystrixCommand + public List getUsers(List ids) { + logger.info("[getUsers][准备调用 user-service 获取多个用户({})详情]", ids); + String[] users = restTemplate.getForEntity("http://127.0.0.1:18080/user/batch_get?ids=" + StringUtils.join(ids, ',') + , String[].class).getBody(); + return users == null || users.length == 0 ? Collections.emptyList() : Arrays.asList(users); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/resources/application.yml b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/resources/application.yml new file mode 100644 index 000000000..f63f8bf19 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01-cluster/src/main/resources/application.yml @@ -0,0 +1,14 @@ +management: + endpoints: + web: + exposure: + include: 'hystrix.stream' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + +spring: + application: + name: hystrix-demo # 应用名 + +eureka: + client: + service-url: + defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址 diff --git a/labx-23/labx-23-scn-hystrix-demo01/pom.xml b/labx-23/labx-23-scn-hystrix-demo01/pom.xml new file mode 100644 index 000000000..6b4d5e182 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/pom.xml @@ -0,0 +1,58 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-demo01 + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java new file mode 100644 index 000000000..5620feaa0 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java @@ -0,0 +1,22 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableCircuitBreaker // 声明开启断路器 +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java new file mode 100644 index 000000000..8af86c48c --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CacheDemoController.java @@ -0,0 +1,33 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CacheDemoService; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +@RequestMapping("/cache-demo") +public class CacheDemoController { + + @Autowired + private CacheDemoService cacheDemoService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + String userB = cacheDemoService.getUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + + @GetMapping("/update_user") + public String updateUser(@RequestParam("id") Integer id) { + String userA = cacheDemoService.getUser(id); + cacheDemoService.updateUser(id); + String userC = cacheDemoService.getUser(id); + return userC; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java new file mode 100644 index 000000000..df3bac8ae --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/CollapserDemoController.java @@ -0,0 +1,46 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.service.CollapserDemoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +@RestController +@RequestMapping("/collapser-demo") +public class CollapserDemoController { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoController.class); + + @Autowired + private CollapserDemoService collapserDemoService; + + @GetMapping("/test") + public void test() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(1); + Future user02 = collapserDemoService.getUserFuture(2); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + + + @GetMapping("/test_02") + public void test02() throws ExecutionException, InterruptedException { + logger.info("[test][准备获取用户信息]"); + Future user01 = collapserDemoService.getUserFuture(2); + Future user02 = collapserDemoService.getUserFuture(1); + logger.info("[test][提交获取用户信息]"); + + logger.info("[test][user({}) 的结果为({})]", 1, user01.get()); + logger.info("[test][user({}) 的结果为({})]", 2, user02.get()); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java new file mode 100644 index 000000000..47db0bf24 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java new file mode 100644 index 000000000..99b732608 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/filter/HystrixRequestContextFilter.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.filter; + +import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import java.io.IOException; + +@Component +@WebFilter(urlPatterns = "/") +public class HystrixRequestContextFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + // 初始化 HystrixRequestContext + HystrixRequestContext context = HystrixRequestContext.initializeContext(); + // 继续过滤器 + try { + chain.doFilter(request, response); + } finally { + // 销毁 HystrixRequestContext + context.close(); + } + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java new file mode 100644 index 000000000..0241062d6 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CacheDemoService.java @@ -0,0 +1,43 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; +import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class CacheDemoService { + + private Logger logger = LoggerFactory.getLogger(CacheDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCommand(fallbackMethod = "getUserFallback") + @CacheResult(cacheKeyMethod = "genGetUserCacheKey") + public String getUser(Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + @HystrixCommand + @CacheRemove(commandKey = "getUser", cacheKeyMethod = "genGetUserCacheKey") + public void updateUser(Integer id) { + logger.info("[updateUser][更新用户({})详情]", id); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + + public String genGetUserCacheKey(Integer id) { + return "USER_" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java new file mode 100644 index 000000000..4006bd492 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-demo01/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/service/CollapserDemoService.java @@ -0,0 +1,44 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.service; + +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + +@Service +public class CollapserDemoService { + + private Logger logger = LoggerFactory.getLogger(CollapserDemoService.class); + + @Autowired + private RestTemplate restTemplate; + + @HystrixCollapser( + batchMethod = "getUsers", + collapserProperties = { + @HystrixProperty(name = "timerDelayInMilliseconds", value = "10000") // 演示,所以设置的时间较长 + } + ) + public Future getUserFuture(Integer id) { + throw new RuntimeException("This method body should not be executed"); + } + + @HystrixCommand + public List getUsers(List ids) { + logger.info("[getUsers][准备调用 user-service 获取多个用户({})详情]", ids); + String[] users = restTemplate.getForEntity("http://127.0.0.1:18080/user/batch_get?ids=" + StringUtils.join(ids, ',') + , String[].class).getBody(); + return users == null || users.length == 0 ? Collections.emptyList() : Arrays.asList(users); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/pom.xml b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/pom.xml new file mode 100644 index 000000000..5dbf7a820 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/pom.xml @@ -0,0 +1,85 @@ + + + + labx-23-scn-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dubbo-demo-application + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + cn.iocoder.springboot.labs + labx-23-scn-hystrix-dubbo-demo-user-service-api + 1.0-SNAPSHOT + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-dubbo + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java new file mode 100644 index 000000000..fc9b5e6c8 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/DemoApplication.java @@ -0,0 +1,15 @@ +package cn.iocoder.springcloud.labx23.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; + +@SpringBootApplication +@EnableCircuitBreaker // 声明开启断路器 +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java new file mode 100644 index 000000000..ae52860fc --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/java/cn/iocoder/springcloud/labx23/demo/controller/DemoController.java @@ -0,0 +1,35 @@ +package cn.iocoder.springcloud.labx23.demo.controller; + +import cn.iocoder.springcloud.labx23.userservice.api.UserService; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.dubbo.config.annotation.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Reference(protocol = "dubbo", version = "1.0.0") + private UserService userService; + + @GetMapping("/get_user") + @HystrixCommand(fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return userService.getUser(id); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable)); + return "mock:User:" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/resources/application.yaml b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/resources/application.yaml new file mode 100644 index 000000000..e41d088e1 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-application/src/main/resources/application.yaml @@ -0,0 +1,17 @@ +spring: + application: + name: demo-consumer + cloud: + # Nacos 作为注册中心的配置项 + nacos: + discovery: + server-addr: 127.0.0.1:8848 + +# Dubbo 配置项,对应 DubboConfigurationProperties 类 +dubbo: + # Dubbo 服务注册中心配置,对应 RegistryConfig 类 + registry: + address: spring-cloud://127.0.0.1:8848 # 指定 Dubbo 服务注册中心的地址 + # Spring Cloud Alibaba Dubbo 专属配置项,对应 DubboCloudProperties 类 + cloud: + subscribed-services: user-service # 设置订阅的应用列表,默认为 * 订阅所有应用。 diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/pom.xml b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/pom.xml new file mode 100644 index 000000000..58ed414e1 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/pom.xml @@ -0,0 +1,14 @@ + + + + labx-23-scn-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dubbo-demo-user-service-api + + diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springcloud/labx23/userservice/api/UserService.java b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springcloud/labx23/userservice/api/UserService.java new file mode 100644 index 000000000..a27ae4eb4 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service-api/src/main/java/cn/iocoder/springcloud/labx23/userservice/api/UserService.java @@ -0,0 +1,7 @@ +package cn.iocoder.springcloud.labx23.userservice.api; + +public interface UserService { + + String getUser(Integer id); + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/pom.xml b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/pom.xml new file mode 100644 index 000000000..7dbb598d1 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/pom.xml @@ -0,0 +1,73 @@ + + + + labx-23-scn-hystrix-dubbo-demo + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dubbo-demo-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + 2.2.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + ${spring.cloud.alibaba.version} + pom + import + + + + + + + + cn.iocoder.springboot.labs + labx-23-scn-hystrix-dubbo-demo-user-service-api + 1.0-SNAPSHOT + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-dubbo + + + + diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java new file mode 100644 index 000000000..4c8cff750 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloud.labx23.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class UserServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(UserServiceApplication.class); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/service/UserServiceImpl.java b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/service/UserServiceImpl.java new file mode 100644 index 000000000..2215bdc30 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/service/UserServiceImpl.java @@ -0,0 +1,13 @@ +package cn.iocoder.springcloud.labx23.userservice.service; + +import cn.iocoder.springcloud.labx23.userservice.api.UserService; + +@org.apache.dubbo.config.annotation.Service(protocol = "dubbo", version = "1.0.0") +public class UserServiceImpl implements UserService { + + @Override + public String getUser(Integer id) { + return "User:" + id; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml new file mode 100644 index 000000000..f62232a7d --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/labx-23-scn-hystrix-dubbo-demo-user-service/src/main/resources/application.yaml @@ -0,0 +1,24 @@ +spring: + application: + name: user-service + cloud: + # Nacos 作为注册中心的配置项 + nacos: + discovery: + server-addr: 127.0.0.1:8848 # Nacos 服务器地址 + +# Dubbo 配置项,对应 DubboConfigurationProperties 类 +dubbo: + scan: + base-packages: cn.iocoder.springcloud.labx23.userservice.service # 指定 Dubbo 服务实现类的扫描基准包 + # Dubbo 服务暴露的协议配置,对应 ProtocolConfig Map + protocols: + dubbo: + name: dubbo # 协议名称 + port: -1 # 协议端口,-1 表示自增端口,从 20880 开始 + # Dubbo 服务注册中心配置,对应 RegistryConfig 类 + registry: + address: spring-cloud://127.0.0.1:8848 # 指定 Dubbo 服务注册中心的地址 + # Spring Cloud Alibaba Dubbo 专属配置项,对应 DubboCloudProperties 类 + cloud: + subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用。 diff --git a/labx-23/labx-23-scn-hystrix-dubbo-demo/pom.xml b/labx-23/labx-23-scn-hystrix-dubbo-demo/pom.xml new file mode 100644 index 000000000..3b2c63630 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-dubbo-demo/pom.xml @@ -0,0 +1,22 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-dubbo-demo + pom + + + labx-23-scn-hystrix-dubbo-demo-user-service + labx-23-scn-hystrix-dubbo-demo-user-service-api + labx-23-scn-hystrix-dubbo-demo-application + + + + diff --git a/labx-23/labx-23-scn-hystrix-feign/pom.xml b/labx-23/labx-23-scn-hystrix-feign/pom.xml new file mode 100644 index 000000000..b80eb748f --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/pom.xml @@ -0,0 +1,64 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-scn-hystrix-feign + + + 1.8 + 1.8 + 2.2.4.RELEASE + Hoxton.SR1 + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring.cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-netflix-hystrix + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + diff --git a/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java new file mode 100644 index 000000000..7d36b4cc9 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/DemoApplication.java @@ -0,0 +1,24 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableCircuitBreaker // 声明开启断路器 +@EnableFeignClients // 开启 Feign Client 功能 +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/FeignDemoController.java b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/FeignDemoController.java new file mode 100644 index 000000000..dc10ae789 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/controller/FeignDemoController.java @@ -0,0 +1,27 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.controller; + +import cn.iocoder.springcloud.labx23.hystrixdemo.feign.UserServiceFeignClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +@RequestMapping("/feign-demo") +public class FeignDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private UserServiceFeignClient userServiceFeignClient; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return userServiceFeignClient.getUser(id); + } + +} diff --git a/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/fallback/UserServiceFeignClientFallbackFactory.java b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/fallback/UserServiceFeignClientFallbackFactory.java new file mode 100644 index 000000000..dd8ba05d6 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/fallback/UserServiceFeignClientFallbackFactory.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.fallback; + +import cn.iocoder.springcloud.labx23.hystrixdemo.feign.UserServiceFeignClient; +import feign.hystrix.FallbackFactory; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class UserServiceFeignClientFallbackFactory implements FallbackFactory { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public UserServiceFeignClient create(Throwable cause) { + return new UserServiceFeignClient() { + + @Override + public String getUser(Integer id) { + logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(cause)); + return "mock:User:" + id; + } + + }; + } + +} diff --git a/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/feign/UserServiceFeignClient.java b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/feign/UserServiceFeignClient.java new file mode 100644 index 000000000..30646a559 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/src/main/java/cn/iocoder/springcloud/labx23/hystrixdemo/feign/UserServiceFeignClient.java @@ -0,0 +1,14 @@ +package cn.iocoder.springcloud.labx23.hystrixdemo.feign; + +import cn.iocoder.springcloud.labx23.hystrixdemo.fallback.UserServiceFeignClientFallbackFactory; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = "user-service", url = "http://127.0.0.1:18080", fallbackFactory = UserServiceFeignClientFallbackFactory.class) +public interface UserServiceFeignClient { + + @GetMapping("/user/get") + String getUser(@RequestParam("id") Integer id); + +} diff --git a/labx-23/labx-23-scn-hystrix-feign/src/main/resources/application.yaml b/labx-23/labx-23-scn-hystrix-feign/src/main/resources/application.yaml new file mode 100644 index 000000000..50c9655e9 --- /dev/null +++ b/labx-23/labx-23-scn-hystrix-feign/src/main/resources/application.yaml @@ -0,0 +1,3 @@ +feign: + hystrix: + enabled: true # 开启 Hystrix 对 Feign 的支持,默认为 false 关闭。 diff --git a/labx-23/labx-23-user-service/pom.xml b/labx-23/labx-23-user-service/pom.xml new file mode 100644 index 000000000..b855f8628 --- /dev/null +++ b/labx-23/labx-23-user-service/pom.xml @@ -0,0 +1,44 @@ + + + + labx-23 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/labx-23/labx-23-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java b/labx-23/labx-23-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java new file mode 100644 index 000000000..c48b8a299 --- /dev/null +++ b/labx-23/labx-23-user-service/src/main/java/cn/iocoder/springcloud/labx23/userservice/UserServiceApplication.java @@ -0,0 +1,40 @@ +package cn.iocoder.springcloud.labx23.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +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; +import java.util.stream.Collectors; + +@SpringBootApplication +public class UserServiceApplication { + + @RestController + @RequestMapping("/user") + public class UserController { + + @GetMapping("/get") + public String get(@RequestParam("id") Integer id) { + return "User:" + id; + } + + @GetMapping("/batch_get") + public List batchGet(@RequestParam("ids") List ids) { + return ids.stream().map(id -> "User:" + id).collect(Collectors.toList()); + } + + } + + public static void main(String[] args) { + // 设置端口 + System.setProperty("server.port", "18080"); + + // 应用启动 + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/labx-23/pom.xml b/labx-23/pom.xml new file mode 100644 index 000000000..0cdfdfcd7 --- /dev/null +++ b/labx-23/pom.xml @@ -0,0 +1,30 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-23 + pom + + labx-23-user-service + + labx-23-scn-hystrix-demo01 + + labx-23-scn-hystrix-actuator + labx-23-scn-hystrix-dashboard + + labx-23-scn-hystrix-demo01-cluster + labx-23-scn-hystrix-dashboard-turbine + + labx-23-scn-hystrix-feign + + labx-23-scn-hystrix-dubbo-demo + + + diff --git "a/labx-23/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" "b/labx-23/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..e7632a098 --- /dev/null +++ "b/labx-23/\343\200\212\350\212\213\351\201\223 Spring Cloud Netflix \346\234\215\345\212\241\345\256\271\351\224\231 Hystrix \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/labx-24/labx-24-resilience4j-demo01/pom.xml b/labx-24/labx-24-resilience4j-demo01/pom.xml new file mode 100644 index 000000000..978b5d5b3 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/pom.xml @@ -0,0 +1,60 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-24-resilience4j-demo01 + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + io.github.resilience4j + resilience4j-spring-cloud2 + 1.4.0 + + + + + org.aspectj + aspectjrt + 1.9.5 + + + org.aspectj + aspectjweaver + 1.9.5 + + + + + diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java new file mode 100644 index 000000000..288518c94 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/BulkheadDemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/BulkheadDemoController.java new file mode 100644 index 000000000..8109bf00a --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/BulkheadDemoController.java @@ -0,0 +1,30 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/bulkhead-demo") +public class BulkheadDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @Bulkhead(name = "backendC", fallbackMethod = "getUserFallback", type = Bulkhead.Type.SEMAPHORE) + public String getUser(@RequestParam("id") Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java new file mode 100644 index 000000000..6cc3269b7 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @CircuitBreaker(name = "backendA", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RateLimiterDemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RateLimiterDemoController.java new file mode 100644 index 000000000..e635f233a --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RateLimiterDemoController.java @@ -0,0 +1,28 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.ratelimiter.annotation.RateLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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; + +@RestController +@RequestMapping("/rate-limiter-demo") +public class RateLimiterDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @GetMapping("/get_user") + @RateLimiter(name = "backendB", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + return "User:" + id; + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RetryDemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RetryDemoController.java new file mode 100644 index 000000000..e69593986 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/RetryDemoController.java @@ -0,0 +1,34 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.retry.annotation.Retry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +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 org.springframework.web.client.RestTemplate; + +@RestController +@RequestMapping("/retry-demo") +public class RetryDemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/get_user") + @Retry(name = "backendE", fallbackMethod = "getUserFallback") + public String getUser(@RequestParam("id") Integer id) { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody(); + } + + public String getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/ThreadPoolBulkheadDemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/ThreadPoolBulkheadDemoController.java new file mode 100644 index 000000000..03afb1109 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/ThreadPoolBulkheadDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/thread-pool-bulkhead-demo") +public class ThreadPoolBulkheadDemoController { + + @Autowired + private ThreadPoolBulkheadService threadPoolBulkheadService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + threadPoolBulkheadService.getUser0(id); + return threadPoolBulkheadService.getUser0(id).get(); + } + + @Service + public static class ThreadPoolBulkheadService { + + private Logger logger = LoggerFactory.getLogger(ThreadPoolBulkheadService.class); + + @Bulkhead(name = "backendD", fallbackMethod = "getUserFallback", type = Bulkhead.Type.THREADPOOL) + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/TimeLimiterDemoController.java b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/TimeLimiterDemoController.java new file mode 100644 index 000000000..3c8a4b01e --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/TimeLimiterDemoController.java @@ -0,0 +1,49 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import io.github.resilience4j.bulkhead.annotation.Bulkhead; +import io.github.resilience4j.timelimiter.annotation.TimeLimiter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +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.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@RestController +@RequestMapping("/time-limiter-demo") +public class TimeLimiterDemoController { + + @Autowired + private TimeLimiterService timeLimiterService; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) throws ExecutionException, InterruptedException { + return timeLimiterService.getUser0(id).get(); + } + + @Service + public static class TimeLimiterService { + + private Logger logger = LoggerFactory.getLogger(TimeLimiterService.class); + + @Bulkhead(name = "backendD", type = Bulkhead.Type.THREADPOOL) + @TimeLimiter(name = "backendF", fallbackMethod = "getUserFallback") + public CompletableFuture getUser0(Integer id) throws InterruptedException { + logger.info("[getUser][id({})]", id); + Thread.sleep(10 * 1000L); // sleep 10 秒 + return CompletableFuture.completedFuture("User:" + id); + } + + public CompletableFuture getUserFallback(Integer id, Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, throwable.getClass().getSimpleName()); + return CompletableFuture.completedFuture("mock:User:" + id); + } + + } + +} diff --git a/labx-24/labx-24-resilience4j-demo01/src/main/resources/application.yml b/labx-24/labx-24-resilience4j-demo01/src/main/resources/application.yml new file mode 100644 index 000000000..6a5b2ad75 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo01/src/main/resources/application.yml @@ -0,0 +1,51 @@ +resilience4j: + # Resilience4j 的断路器配置项,对应 CircuitBreakerProperties 属性类 + circuitbreaker: + instances: + backendA: + failure-rate-threshold: 50 # 熔断器关闭状态和半开状态使用的同一个失败率阈值,单位:百分比。默认为 50 + ring-buffer-size-in-closed-state: 5 # 熔断器关闭状态的缓冲区大小,不会限制线程的并发量,在熔断器发生状态转换前所有请求都会调用后端服务。默认为 100 + ring-buffer-size-in-half-open-state: 5 # 熔断器半开状态的缓冲区大小,会限制线程的并发量。例如,缓冲区为 10 则每次只会允许 10 个请求调用后端服务。默认为 10 + wait-duration-in-open-state : 5000 # 熔断器从打开状态转变为半开状态等待的时间,单位:微秒 + automatic-transition-from-open-to-half-open-enabled: true # 如果置为 true,当等待时间结束会自动由打开变为半开;若置为 false,则需要一个请求进入来触发熔断器状态转换。默认为 true + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的限流器配置项,对应 RateLimiterProperties 属性类 + ratelimiter: + instances: + backendB: + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 + limit-refresh-period: 10s # 每个周期的时长,单位:微秒。默认为 500 + timeout-duration: 5s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s + register-health-indicator: true # 是否注册到健康监测 + + # Resilience4j 的信号量 Bulkhead 配置项,对应 BulkheadConfigurationProperties 属性类 + bulkhead: + instances: + backendC: + max-concurrent-calls: 1 # 并发调用数。默认为 25 + max-wait-duration: 5s # 并发调用到达上限时,阻塞等待的时长,单位:微秒。默认为 0 + # Resilience4j 的线程池 Bulkhead 配置项,对应 ThreadPoolBulkheadProperties 属性类 + thread-pool-bulkhead: + instances: + backendD: + max-thread-pool-size: 1 # 线程池的最大大小。默认为 Runtime.getRuntime().availableProcessors() + core-thread-pool-size: 1 # 线程池的核心大小。默认为 Runtime.getRuntime().availableProcessors() - 1 + queue-capacity: 200 # 线程池的队列大小。默认为 100 + keep-alive-duration: 100s # 超过核心大小的线程,空闲存活时间。默认为 20 毫秒 + + # Resilience4j 的重试 Retry 配置项,对应 RetryProperties 属性类 + retry: + instances: + backendE: + max-retry-Attempts: 3 # 最大重试次数。默认为 3 + wait-duration: 5s # 下次重试的间隔,单位:微秒。默认为 500 毫秒 + retry-exceptions: # 需要重试的异常列表。默认为空 + ingore-exceptions: # 需要忽略的异常列表。默认为空 + + # Resilience4j 的超时限制器 TimeLimiter 配置项,对应 TimeLimiterProperties 属性类 + timelimiter: + instances: + backendF: + timeout-duration: 1s # 等待超时时间,单位:微秒。默认为 1 秒 + cancel-running-future: true # 当等待超时时,是否关闭取消线程。默认为 true diff --git a/labx-24/labx-24-resilience4j-demo02/pom.xml b/labx-24/labx-24-resilience4j-demo02/pom.xml new file mode 100644 index 000000000..8c34472df --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo02/pom.xml @@ -0,0 +1,48 @@ + + + + lab-59 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-24-resilience4j-demo02 + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.cloud + spring-cloud-starter-circuitbreaker-resilience4j + 1.0.2.RELEASE + + + + + diff --git a/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java new file mode 100644 index 000000000..288518c94 --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/DemoApplication.java @@ -0,0 +1,20 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class DemoApplication { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/config/Resilience4jConfig.java b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/config/Resilience4jConfig.java new file mode 100644 index 000000000..ab56c7b2f --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/config/Resilience4jConfig.java @@ -0,0 +1,80 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.config; + +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import io.github.resilience4j.timelimiter.TimeLimiterConfig; +import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory; +import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder; +import org.springframework.cloud.client.circuitbreaker.Customizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; +import java.util.function.Consumer; +import java.util.function.Function; + +@Configuration +public class Resilience4jConfig { + + @Bean + public Customizer resilience4JCircuitBreakerFactoryCustomizer() { + return new Customizer() { + + @Override + public void customize(Resilience4JCircuitBreakerFactory resilience4JCircuitBreakerFactory) { + // 设置默认的配置 + resilience4JCircuitBreakerFactory.configureDefault(new Function() { + + @Override + public Resilience4JConfigBuilder.Resilience4JCircuitBreakerConfiguration apply(String id) { + // 创建 TimeLimiterConfig 对象 + TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.ofDefaults(); // 默认 + // 创建 CircuitBreakerConfig 对象 + CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.ofDefaults(); // 默认 + // 创建 Resilience4JCircuitBreakerConfiguration 对象 + return new Resilience4JConfigBuilder(id) + .timeLimiterConfig(timeLimiterConfig) + .circuitBreakerConfig(circuitBreakerConfig) + .build(); + } + + }); + // 设置编号为 "slow" 的自定义配置 + resilience4JCircuitBreakerFactory.configure(new Consumer() { + @Override + public void accept(Resilience4JConfigBuilder resilience4JConfigBuilder) { + // 创建 TimeLimiterConfig 对象 + TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)) // 自定义 + .build(); + // 创建 CircuitBreakerConfig 对象 + CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() // 自定义 + .slidingWindow(5, 5, CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) + .build(); + // 设置 Resilience4JCircuitBreakerConfiguration 对象 + resilience4JConfigBuilder + .timeLimiterConfig(timeLimiterConfig) + .circuitBreakerConfig(circuitBreakerConfig); + } + }, "slow"); + } + + }; + } + +// @Bean +// public Customizer defaultCustomizer() { +// return factory -> factory.configureDefault( +// id -> new Resilience4JConfigBuilder(id) +// .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build()) +// .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()) +// .build()); +// } + +// @Bean +// public Customizer slowCustomizer() { +// return factory -> factory.configure(builder -> builder +// .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(2)).build()) +// .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()), +// "slow"); +// } + +} diff --git a/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java new file mode 100644 index 000000000..b7c21dcdd --- /dev/null +++ b/labx-24/labx-24-resilience4j-demo02/src/main/java/cn/iocoder/springcloud/labx24/resilience4jdemo/controller/DemoController.java @@ -0,0 +1,50 @@ +package cn.iocoder.springcloud.labx24.resilience4jdemo.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; +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 org.springframework.web.client.RestTemplate; + +import java.util.function.Function; +import java.util.function.Supplier; + +@RestController +@RequestMapping("/demo") +public class DemoController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private CircuitBreakerFactory circuitBreakerFactory; + + @GetMapping("/get_user") + public String getUser(@RequestParam("id") Integer id) { + return circuitBreakerFactory.create("slow").run(new Supplier() { + + @Override + public String get() { + logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id); + return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + + id, String.class).getBody(); + } + + }, new Function() { + + @Override + public String apply(Throwable throwable) { + logger.info("[getUserFallback][id({}) exception({})]", id, + throwable.getClass().getSimpleName()); + return "mock:User:" + id; + } + + }); + } +} diff --git a/labx-24/labx-24-user-service/pom.xml b/labx-24/labx-24-user-service/pom.xml new file mode 100644 index 000000000..9bc10c4e4 --- /dev/null +++ b/labx-24/labx-24-user-service/pom.xml @@ -0,0 +1,40 @@ + + + + labx-24 + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-24-user-service + + + 1.8 + 1.8 + 2.2.4.RELEASE + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + diff --git a/labx-24/labx-24-user-service/src/main/java/cn/iocoder/springcloud/labx24/userservice/UserServiceApplication.java b/labx-24/labx-24-user-service/src/main/java/cn/iocoder/springcloud/labx24/userservice/UserServiceApplication.java new file mode 100644 index 000000000..6a1e11887 --- /dev/null +++ b/labx-24/labx-24-user-service/src/main/java/cn/iocoder/springcloud/labx24/userservice/UserServiceApplication.java @@ -0,0 +1,40 @@ +package cn.iocoder.springcloud.labx24.userservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +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; +import java.util.stream.Collectors; + +@SpringBootApplication +public class UserServiceApplication { + + @RestController + @RequestMapping("/user") + public class UserController { + + @GetMapping("/get") + public String get(@RequestParam("id") Integer id) { + return "User:" + id; + } + + @GetMapping("/batch_get") + public List batchGet(@RequestParam("ids") List ids) { + return ids.stream().map(id -> "User:" + id).collect(Collectors.toList()); + } + + } + + public static void main(String[] args) { + // 设置端口 + System.setProperty("server.port", "18080"); + + // 应用启动 + SpringApplication.run(UserServiceApplication.class, args); + } + +} diff --git a/labx-24/pom.xml b/labx-24/pom.xml new file mode 100644 index 000000000..26b9d42af --- /dev/null +++ b/labx-24/pom.xml @@ -0,0 +1,20 @@ + + + + labs-parent + cn.iocoder.springboot.labs + 1.0-SNAPSHOT + + 4.0.0 + + labx-24 + + + labx-24-user-service + labx-24-resilience4j-demo01 + labx-24-resilience4j-demo02 + + + diff --git "a/labx-24/\343\200\212\350\212\213\351\201\223 Spring Cloud \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" "b/labx-24/\343\200\212\350\212\213\351\201\223 Spring Cloud \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" new file mode 100644 index 000000000..d46689cc1 --- /dev/null +++ "b/labx-24/\343\200\212\350\212\213\351\201\223 Spring Cloud \346\234\215\345\212\241\345\256\271\351\224\231 Resilience4j \345\205\245\351\227\250\343\200\213.md" @@ -0,0 +1 @@ + diff --git a/pom.xml b/pom.xml index e89acdfac..f94b8e36b 100644 --- a/pom.xml +++ b/pom.xml @@ -11,82 +11,92 @@ - lab-01 - lab-02 - lab-03 - lab-04 - lab-05 - lab-06 - lab-07 - lab-08 - lab-09 - lab-10 - lab-11 - lab-12 - lab-13 - lab-14 - lab-15 - lab-16 - lab-17 - lab-18 - lab-19 - lab-20 - lab-21 - lab-22 - lab-23 - lab-24 - lab-25 - lab-26 - lab-27 - lab-28 - lab-29 - lab-30 - lab-31 - lab-32 - lab-33 - lab-34 - lab-35 - lab-36 - lab-37 - lab-38 - lab-39 - lab-40 - lab-41 - lab-42 - lab-43 - lab-44 - lab-45 - lab-46 - lab-47 - lab-48 - lab-49 - lab-50 - lab-51 - lab-52 - lab-53 - lab-54 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - labx-01 - labx-02 - labx-03 - labx-04 - labx-05 - labx-06 - labx-07 - labx-08 - labx-09 - labx-10 - labx-11 - labx-12 - labx-13 - labx-14 - labx-15 - labx-16 - labx-17 - labx-18 - labx-19 - labx-20 + + + + + + + + + + + + + + + + + + + + + + + +