增加 Hystrix 入门示例(Hystrix Turbine)

This commit is contained in:
YunaiV
2020-05-13 08:46:15 +08:00
parent 9af1942c26
commit 8aeb88fdcb
14 changed files with 448 additions and 4 deletions

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-23-scn-hystrix-dashboard-turbine</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -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);
}
}

View File

@@ -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')

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-23-scn-hystrix-demo01-cluster</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- 实现对 Actuator 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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<String> user01 = collapserDemoService.getUserFuture(1);
Future<String> 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<String> user01 = collapserDemoService.getUserFuture(2);
Future<String> user02 = collapserDemoService.getUserFuture(1);
logger.info("[test][提交获取用户信息]");
logger.info("[test][user({}) 的结果为({})]", 1, user01.get());
logger.info("[test][user({}) 的结果为({})]", 2, user02.get());
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<String> getUserFuture(Integer id) {
throw new RuntimeException("This method body should not be executed");
}
@HystrixCommand
public List<String> getUsers(List<Integer> 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);
}
}

View File

@@ -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 地址

View File

@@ -12,11 +12,15 @@
<artifactId>labx-23</artifactId>
<packaging>pom</packaging>
<modules>
<module>labx-23-scn-hystrix-demo01</module>
<module>labx-23-user-service</module>
<module>labx-23-scn-hystrix-demo01</module>
<module>labx-23-scn-hystrix-actuator</module>
<module>labx-23-scn-hystrix-dashboard</module>
<module>labx-23-scn-hystrix-demo01-cluster</module>
<module>labx-23-scn-hystrix-dashboard-turbine</module>
</modules>
</project>

View File

@@ -90,9 +90,7 @@
<!-- <module>labx-19</module>-->
<!-- <module>labx-20</module>-->
<!-- <module>labx-21</module>-->
<!-- <module>labx-22</module>-->
<module>labx-22</module>
<module>labx-23</module>
</modules>