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 00000000..15e4f806
--- /dev/null
+++ b/labx-23/labx-23-scn-hystrix-dashboard-turbine/pom.xml
@@ -0,0 +1,74 @@
+
+
+
+ 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
+
+
+
+ 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 00000000..e2a4e01b
--- /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
+@EnableTurbine
+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 00000000..f235f2ac
--- /dev/null
+++ b/labx-23/labx-23-scn-hystrix-dashboard-turbine/src/main/resources/application.yml
@@ -0,0 +1,16 @@
+server:
+ port: 9090
+
+spring:
+ application:
+ name: hystrix-dashboard
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址
+
+turbine:
+ app-config: hystrix-demo
+ combine-host-port: true
+ cluster-name-expression: new String('default')
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 00000000..f2b08653
--- /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 00000000..5620feaa
--- /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 00000000..8af86c48
--- /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 00000000..df3bac8a
--- /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 00000000..47db0bf2
--- /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 00000000..99b73260
--- /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 00000000..0241062d
--- /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 00000000..4006bd49
--- /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 00000000..f63f8bf1
--- /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/pom.xml b/labx-23/pom.xml
index 1a613762..e92a0edb 100644
--- a/labx-23/pom.xml
+++ b/labx-23/pom.xml
@@ -12,11 +12,15 @@
labx-23
pom
- labx-23-scn-hystrix-demo01
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
diff --git a/pom.xml b/pom.xml
index e22d68f1..b0837dbd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,9 +90,7 @@
-
-
-
+ labx-22
labx-23