Преглед изворни кода

更新 user-service 中的 hystrix 熔断处理

reghao пре 8 месеци
родитељ
комит
2d133fc509

+ 0 - 2
user/user-service/src/main/java/cn/reghao/tnb/user/app/UserApplication.java

@@ -2,12 +2,10 @@ package cn.reghao.tnb.user.app;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.netflix.hystrix.EnableHystrix;
 import org.springframework.context.annotation.ComponentScan;
 
 @SpringBootApplication
 @ComponentScan({"cn.reghao.tnb.user", "cn.reghao.tnb.common"})
-@EnableHystrix
 public class UserApplication {
     public static void main(String[] args) {
         SpringApplication.run(UserApplication.class, args);

+ 13 - 0
user/user-service/src/main/java/cn/reghao/tnb/user/app/config/HystrixConfig.java

@@ -0,0 +1,13 @@
+package cn.reghao.tnb.user.app.config;
+
+import org.springframework.cloud.netflix.hystrix.EnableHystrix;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author reghao
+ * @date 2025-07-19 23:00:31
+ */
+@Configuration
+@EnableHystrix
+public class HystrixConfig {
+}

+ 50 - 0
user/user-service/src/main/java/cn/reghao/tnb/user/app/controller/UserFeignController.java

@@ -0,0 +1,50 @@
+package cn.reghao.tnb.user.app.controller;
+
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
+import cn.reghao.tnb.account.api.iface.AccountQuery;
+import cn.reghao.tnb.user.api.dto.UserInfo;
+import cn.reghao.tnb.user.app.service.UserProfileService;
+import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
+import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
+import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
+import io.swagger.v3.oas.annotations.Operation;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author reghao
+ * @date 2025-07-19 23:59:57
+ */
+@RestController
+@RequestMapping("/api/user/feign")
+public class UserFeignController {
+    @DubboReference(check = false, retries = 0, timeout = 60_000)
+    private AccountQuery accountQuery;
+    private final UserProfileService userProfileService;
+
+    public UserFeignController(UserProfileService userProfileService) {
+        this.userProfileService = userProfileService;
+    }
+
+    @Operation(summary = "获取用户资料", description = "N")
+    @GetMapping(value = "/info", produces = MediaType.APPLICATION_JSON_VALUE)
+    @HystrixCommand(fallbackMethod = "getUserInfoFallback", commandProperties = {
+            @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED, value = "false")
+    })
+    public String getUserInfo(@RequestParam("userId") Long userId) {
+        UserInfo userInfo = userProfileService.getUserInfo(userId);
+        return JsonConverter.objectToJson(userInfo);
+    }
+
+    public String getUserInfoFallback(Long userId) {
+        System.out.printf("hystrix fallback with userId %s\n", userId);
+        Map<String, String> map = new HashMap<>();
+        map.put("code", "0");
+        map.put("msg", "hystrix fallback");
+        return JsonConverter.objectToJson(map);
+    }
+}

+ 0 - 6
user/user-service/src/main/java/cn/reghao/tnb/user/app/controller/UserWalletController.java

@@ -9,7 +9,6 @@ import cn.reghao.tnb.user.app.model.dto.WalletDto;
 import cn.reghao.tnb.user.app.model.po.Wallet;
 import cn.reghao.tnb.user.app.model.vo.BillRecord;
 import cn.reghao.tnb.user.app.service.WalletService;
-import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
 import org.springframework.http.MediaType;
@@ -46,17 +45,12 @@ public class UserWalletController {
     @Operation(summary = "获取钱包账单", description = "N")
     @AuthUser
     @GetMapping(value = "/bill", produces = MediaType.APPLICATION_JSON_VALUE)
-    @HystrixCommand(fallbackMethod = "getWalletBillHystrix")
     public String getWalletBill() {
         long loginUser = UserContext.getUser();
         List<BillRecord> list = walletService.getWalletBill(loginUser);
         return WebResult.success(list);
     }
 
-    public String getWalletBillHystrix(){
-        return WebResult.failWithMsg("hystrix fallback");
-    }
-
     @Operation(summary = "向钱包充值", description = "N")
     @AuthUser
     @PostMapping("/charge")

+ 475 - 0
user/user-service/src/test/java/HystrixTest.java

@@ -0,0 +1,475 @@
+import com.netflix.hystrix.*;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author reghao
+ * @date 2025-07-20 11:01:33
+ */
+@Slf4j
+public class HystrixTest {
+    /**
+     * 异常降级
+     * 非HystrixBadRequestException异常:当抛出HystrixBadRequestException时,
+     * 调用程序可以捕获异常,此时不会触发fallback,而其他异常则会触发fallback,
+     * 调用程序将获得fallback逻辑的返回结果。
+     */
+    static class HelloWorldExceptionCommand extends HystrixCommand<String> {
+        private final int n;
+
+        public HelloWorldExceptionCommand(int n) {
+            // 最小配置,指定groupKey
+            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("helloWorldExceptionGroup")));
+            this.n = n;
+        }
+
+        @Override
+        protected String run() throws Exception {
+            log.info(n + "-HelloWorldExceptionCommand A--> " + Thread.currentThread().getName());
+            // 制造异常
+            int i = 1 / n;
+            // 若异常被捕获则不会进入 getFallback()
+            /*try {
+                int i = 1 / n;
+            } catch (Exception e) {
+                log.error("异常:" + e.getMessage());
+            }*/
+
+            log.info(n + "-HelloWorldExceptionCommand B--> " + Thread.currentThread().getName());
+            return n + "执行成功";
+        }
+
+        @Override
+        protected String getFallback() {
+            log.error(n + "-异常降级! C--> " + Thread.currentThread().getName());
+            return n + "执行失败";
+        }
+    }
+
+    /**
+     * 超时降级
+     * run()/construct()运行超时:执行命令的方法超时,将会触发fallback。
+     */
+    static class HelloWorldTimeoutCommand extends HystrixCommand<String> {
+        private final int n;
+
+        public HelloWorldTimeoutCommand(int n) {
+            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("helloWorldTimeoutGroup"))
+                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
+                            /*
+                             * execution.isolation.thread.timeoutInMilliseconds
+                             * 设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,
+                             * 并执行回退逻辑。
+                             * 默认值:1000(毫秒)
+                             */
+                            .withExecutionTimeoutInMilliseconds(500)
+                            /*
+                             * execution.timeout.enabled
+                             * 设置HystrixCommand的执行是否有超时限制。
+                             * 默认值:true
+                             */
+                            .withExecutionTimeoutEnabled(true)
+                            /*
+                             * execution.isolation.thread.interruptOnTimeout
+                             * 设置HystrixCommand的执行是否在超时发生时被中断。
+                             * 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作。
+                             * 默认值:true
+                             */
+                            .withExecutionIsolationThreadInterruptOnTimeout(false)
+                    )
+            );
+            this.n = n;
+        }
+
+        @Override
+        protected String run() throws Exception {
+            log.info(n + "-HelloWorldTimeoutCommand A--> " + Thread.currentThread().getName());
+            if (n == 0) {
+                // 设置超时
+                Thread.sleep(1000);
+            }
+            // 设置withExecutionIsolationThreadInterruptOnTimeout(false)后面代码将会继续执行
+            log.info(n + "-HelloWorldTimeoutCommand B--> " + Thread.currentThread().getName());
+            return n + "执行成功";
+        }
+
+        @Override
+        protected String getFallback() {
+            log.error("超时降级! C--> " + Thread.currentThread().getName());
+            return n + "执行失败";
+        }
+    }
+
+    /**
+     * 触发熔断器熔断
+     * 熔断器开启:当熔断器处于开启的状态,将会触发fallback。
+     */
+    static class HelloWorldBreakerCommand extends HystrixCommand<String> {
+        private final int n;
+
+        public HelloWorldBreakerCommand(int n) {
+            //最小配置,指定groupKey
+            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("helloWorldBreakerGroup"))
+                    .andCommandPropertiesDefaults(
+                            HystrixCommandProperties.Setter()
+                                    /*
+                                     * execution.isolation.thread.timeoutInMilliseconds
+                                     * 设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,
+                                     * 并执行回退逻辑。
+                                     * 默认值:1000(毫秒)
+                                     */
+                                    .withExecutionTimeoutInMilliseconds(1000)
+                                    /*
+                                     * execution.isolation.thread.interruptOnTimeout
+                                     * 设置HystrixCommand的执行是否在超时发生时被中断。
+                                     * 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作。
+                                     * 默认值:true
+                                     */
+                                    .withExecutionIsolationThreadInterruptOnTimeout(true)
+                                    // ** 断路器(Circuit Breaker)属性配置 **
+                                    /*
+                                     * circuitBreaker.enabled
+                                     * 设置断路器是否生效
+                                     * 默认值:true
+                                     */
+                                    .withCircuitBreakerEnabled(true)
+                                    /*
+                                     * circuitBreaker.requestVolumeThreshold
+                                     * 设置在一个滚动窗口中,打开断路器的最少请求数。比如:如果值是20,在一个窗口内(比如10秒),收到19个请求,即使这19个请求都失败了,断路器也不会打开。
+                                     * 默认值:20
+                                     */
+                                    .withCircuitBreakerRequestVolumeThreshold(6)
+                                    /*
+                                     * circuitBreaker.sleepWindowInMilliseconds
+                                     * 设置在断路器被打开,拒绝请求到再次尝试请求的时间间隔。
+                                     * 默认值:5000(毫秒)
+                                     */
+                                    .withCircuitBreakerSleepWindowInMilliseconds(3000)
+                                    /*
+                                     * circuitBreaker.errorThresholdPercentage
+                                     * 设置打开断路器并启动回退逻辑的错误比率。
+                                     * (这个参数的效果受到circuitBreaker.requestVolumeThreshold和滚动时间窗口的时间长度影响)
+                                     * 默认值:50(%)
+                                     */
+                                    .withCircuitBreakerErrorThresholdPercentage(50)
+                    )
+                    //设置核心线程池的大小
+                    .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20))
+            );
+            this.n = n;
+        }
+
+        @Override
+        protected String run() throws Exception {
+            log.info(n + "-HelloWorldTimeoutCommand A--> " + Thread.currentThread().getName());
+            if (n > 0) {
+                // 设置超时
+                Thread.sleep(1000);
+            }
+            // 设置withExecutionIsolationThreadInterruptOnTimeout(true)后面代码将中断执行
+            log.info(n + "-HelloWorldTimeoutCommand B--> " + Thread.currentThread().getName());
+            return n + "执行成功";
+        }
+
+        @Override
+        protected String getFallback() {
+            log.error("熔断降级! C--> " + Thread.currentThread().getName());
+            return n + "执行失败";
+        }
+    }
+
+    /**
+     * 线程池/信号量已满
+     * 当线程池/信号量已满的状态,将会触发fallback。
+     */
+    static class HelloWorldThreadPoolCommand extends HystrixCommand<String> {
+        private final int n;
+
+        public HelloWorldThreadPoolCommand(int n) {
+            super(Setter
+                    // *** 基础属性配置 ***
+                    /*
+                     * CommandGroup是每个命令最少配置的必选参数,在不指定ThreadPoolKey的情况下,
+                     * 字面值用于对不同依赖的线程池/信号区分,也就是在不指定ThreadPoolKey的情况下,
+                     * CommandGroup用于指定线程池的隔离。命令分组用于对依赖操作分组,便于统计、汇总等。
+                     */
+                    .withGroupKey(HystrixCommandGroupKey.Factory.asKey("helloWorldThreadPoolGroup"))
+                    /*
+                     * CommandKey是作为依赖命名,一般来说每个CommandKey代表一个依赖抽象,
+                     * 相同的依赖要使用相同的CommandKey名称。依赖隔离的根本就是对相同CommandKey的依赖做隔离。
+                     * 不同的依赖隔离最好使用不同的线程池(定义不同的ThreadPoolKey)。
+                     * 从HystrixCommand源码的注释也可以看到CommandKey也用于对依赖操作统计、汇总等。
+                     */
+                    .andCommandKey(HystrixCommandKey.Factory.asKey("helloWorldThreadPoolCommand"))
+                    /*
+                     * ThreadPoolKey简单来说就是依赖隔离使用的线程池的键值。
+                     * 当对同一业务依赖做隔离时使用CommandGroup做区分,
+                     * 但是对同一依赖的不同远程调用如(一个是redis 一个是http),可以使用HystrixThreadPoolKey做隔离区分。
+                     * 虽然在业务上都是相同的组,但是需要在资源上做隔离时,可以使用HystrixThreadPoolKey区分。
+                     * (对于每个不同的HystrixThreadPoolKey建议使用不同的CommandKey)
+                     */
+                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("helloWorldThreadPool"))
+                    // *** 设置命令属性配置默认值 ***
+                    .andCommandPropertiesDefaults(
+                            HystrixCommandProperties.Setter()
+                                    // ** 执行属性 **
+                                    /*
+                                     * execution.isolation.strategy
+                                     * 用于设置HystrixCommand执行的隔离策略,有两种选项:
+                                     * THREAD —— 在固定大小线程池中,以单独线程执行,并发请求数受限于线程池大小。
+                                     * SEMAPHORE —— 在调用线程中执行,通过信号量来限制并发量。
+                                     * 默认值:THREAD(ExecutionIsolationStrategy.THREAD)可选值:THREAD,SEMAPHORE
+                                     */
+                                    .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
+                                    /*
+                                     * execution.isolation.thread.timeoutInMilliseconds
+                                     * 设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,
+                                     * 并执行回退逻辑。
+                                     * 默认值:1000(毫秒)
+                                     */
+                                    .withExecutionTimeoutInMilliseconds(1000)
+                                    /*
+                                     * execution.timeout.enabled
+                                     * 设置HystrixCommand的执行是否有超时限制。
+                                     * 默认值:true
+                                     */
+                                    .withExecutionTimeoutEnabled(false)
+                                    /*
+                                     * execution.isolation.thread.interruptOnTimeout
+                                     * 设置HystrixCommand的执行是否在超时发生时被中断。
+                                     * 使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作。
+                                     * 默认值:true
+                                     */
+                                    .withExecutionIsolationThreadInterruptOnTimeout(true)
+                                    /*
+                                     * execution.isolation.semaphore.maxConcurrentRequests
+                                     * 设置当使用ExecutionIsolationStrategy.SEMAPHORE时,HystrixCommand执行方法允许的最大请求数。
+                                     * 如果达到最大并发数时,后续请求会被拒绝。
+                                     * 信号量应该是容器(比如Tomcat)线程池一小部分,不能等于或者略小于容器线程池大小,否则起不到保护作用。
+                                     * 默认值:10
+                                     */
+                                    .withExecutionIsolationSemaphoreMaxConcurrentRequests(10)
+                                    // ** 回退属性 **
+                                    // 下面的属性控制HystrixCommand.getFallback()执行。
+                                    // 这些属性对ExecutionIsolationStrategy.THREAD和ExecutionIsolationStrategy.SEMAPHORE都有效。
+                                    /*
+                                     * fallback.isolation.semaphore.maxConcurrentRequests
+                                     * 设置调用线程产生的HystrixCommand.getFallback()方法的允许最大请求数目。
+                                     * 如果达到最大并发数目,后续请求将会被拒绝,如果没有实现回退,则抛出异常。
+                                     * (这里需要注意一点,这个变量的命名不是很规范,它实际上对THREAD和SEMAPHORE两种隔离策略都生效)
+                                     * 默认值:10
+                                     */
+                                    .withFallbackIsolationSemaphoreMaxConcurrentRequests(10)
+                                    /*
+                                     * fallback.enabled
+                                     * 该属性决定当前的调用故障或者拒绝发生时,是否调用HystrixCommand.getFallback()。
+                                     * 默认值:true
+                                     */
+                                    .withFallbackEnabled(true)
+                                    // ** 断路器(Circuit Breaker)属性配置 **
+                                    /*
+                                     * circuitBreaker.enabled
+                                     * 设置断路器是否生效
+                                     * 默认值:true
+                                     */
+                                    .withCircuitBreakerEnabled(true)
+                                    /*
+                                     * circuitBreaker.requestVolumeThreshold
+                                     * 设置在一个滚动窗口中,打开断路器的最少请求数。比如:如果值是20,在一个窗口内(比如10秒),收到19个请求,即使这19个请求都失败了,断路器也不会打开。
+                                     * 默认值:20
+                                     */
+                                    .withCircuitBreakerRequestVolumeThreshold(5)
+                                    /*
+                                     * circuitBreaker.sleepWindowInMilliseconds
+                                     * 设置在断路器被打开,拒绝请求到再次尝试请求的时间间隔。
+                                     * 默认值:5000(毫秒)
+                                     */
+                                    .withCircuitBreakerSleepWindowInMilliseconds(5000)
+                                    /*
+                                     * circuitBreaker.errorThresholdPercentage
+                                     * 设置打开断路器并启动回退逻辑的错误比率。
+                                     * (这个参数的效果受到circuitBreaker.requestVolumeThreshold和滚动时间窗口的时间长度影响)
+                                     * 默认值:50(%)
+                                     */
+                                    .withCircuitBreakerErrorThresholdPercentage(50)
+                                    /*
+                                     * circuitBreaker.forceOpen
+                                     * 如果该属性设置为true,强制断路器进入打开状态,将会拒绝所有的请求。
+                                     * 该属性优先级比circuitBreaker.forceClosed高
+                                     * 默认值:false
+                                     */
+                                    .withCircuitBreakerForceOpen(false)
+                                    /*
+                                     * circuitBreaker.forceClosed
+                                     * 如果该属性设置为true,强制断路器进入关闭状态,将会允许所有的请求,无视错误率。
+                                     * 默认值:false
+                                     */
+                                    .withCircuitBreakerForceClosed(false)
+                                    // ** 请求上下文属性配置 **
+                                    /*
+                                     * requestCache.enabled
+                                     * 设置HystrixCommand.getCacheKey()是否启用,由HystrixRequestCache通过请求缓存提供去重复数据功能。
+                                     * (请求结果缓存需要配合HystrixRequestContext使用,具体应用可以自行查阅)
+                                     * 默认值:true
+                                     */
+                                    .withRequestCacheEnabled(true)
+                                    /*
+                                     * requestLog.enabled
+                                     * 设置HystrixCommand执行和事件是否要记录日志到HystrixRequestLog。
+                                     * 默认值:true
+                                     */
+                                    .withRequestLogEnabled(true)
+                    )
+                    // *** 设置线程池属性配置默认值 ***
+                    .andThreadPoolPropertiesDefaults(
+                            HystrixThreadPoolProperties.Setter()
+                                    /*
+                                     * coreSize
+                                     * 设置核心线程池的大小(这个值和ThreadPoolExecutor的coreSize的含义不一样)
+                                     * 默认值:10
+                                     */
+                                    .withCoreSize(10)
+                                    /*
+                                     * maximumSize
+                                     * 1.5.9新增属性,设置线程池最大值。
+                                     * 这个是在不开始拒绝HystrixCommand的情况下支持的最大并发数。
+                                     * 这个属性起作用的前提是设置了allowMaximumSizeToDivergeFromCoreSize。
+                                     * 1.5.9之前,核心线程池大小和最大线程池大小总是相同的。
+                                     * 默认值:10
+                                     */
+                                    .withMaximumSize(10)
+                                    /*
+                                     * maxQueueSize
+                                     * 设置BlockingQueue最大的队列值。如果设置为-1,
+                                     * 那么使用SynchronousQueue,否则正数将会使用LinkedBlockingQueue。
+                                     * 如果需要去除这些限制,允许队列动态变化,可以参考queueSizeRejectionThreshold属性。
+                                     * 修改SynchronousQueue和LinkedBlockingQueue需要重启。
+                                     * 默认值:-1
+                                     */
+                                    .withMaxQueueSize(-1)
+                                    /*
+                                     * queueSizeRejectionThreshold
+                                     * 设置队列拒绝的阈值—-一个人为设置的拒绝访问的最大队列值,即使当前队列元素还没达到maxQueueSize。
+                                     * 当将一个线程放入队列等待执行时,HystrixCommand使用该属性。
+                                     * 注意:如果maxQueueSize设置为-1,该属性不可用。
+                                     * 默认值:5
+                                     */
+                                    .withQueueSizeRejectionThreshold(5)
+                                    /*
+                                     * keepAliveTimeMinutes
+                                     * 设置存活时间,单位分钟。如果coreSize小于maximumSize,那么该属性控制一个线程从实用完成到被释放的时间。
+                                     * 默认值:1
+                                     */
+                                    .withKeepAliveTimeMinutes(1)
+                                    /*
+                                     * allowMaximumSizeToDivergeFromCoreSize
+                                     * 在1.5.9中新增的属性。该属性允许maximumSize起作用。属性值可以等于或者大于coreSize值,
+                                     * 设置coreSize小于maximumSize的线程池能够支持maximumSize的并发数,
+                                     * 但是会将不活跃的线程返回到系统中去。
+                                     * 默认值:false
+                                     */
+                                    .withAllowMaximumSizeToDivergeFromCoreSize(false)
+                                    /*
+                                     * metrics.rollingStats.timeInMilliseconds
+                                     * 设置统计的滚动窗口的时间段大小。该属性是线程池保持指标时间长短。
+                                     * 默认值:10000(毫秒)
+                                     */
+                                    .withMetricsRollingStatisticalWindowInMilliseconds(10000)
+                                    /*
+                                     * metrics.rollingStats.numBuckets
+                                     * 设置滚动的统计窗口被分成的桶(bucket)的数目。
+                                     * 注意:”metrics.rollingStats.timeInMilliseconds % metrics.rollingStats.numBuckets == 0”必须为true,否则会抛出异常。
+                                     * 默认值:10
+                                     */
+                                    .withMetricsRollingStatisticalWindowBuckets(10)
+                    )
+            );
+            this.n = n;
+        }
+
+        @Override
+        protected String run() throws Exception {
+            log.info(n + "-HelloWorldThreadPoolCommand A--> " + Thread.currentThread().getName());
+            Thread.sleep(10000);
+            log.info(n + "-HelloWorldThreadPoolCommand B--> " + Thread.currentThread().getName());
+            return n + "执行完毕";
+        }
+
+        @Override
+        protected String getFallback() {
+            log.error("线程池/信号量已满 FALLBACK --> !");
+            return "FALLBACK";
+        }
+
+        static class ThreadRunner extends Thread {
+            private int i;
+
+            public ThreadRunner(int i) {
+                this.i = i;
+            }
+
+            @Override
+            public void run() {
+                log.info(new HelloWorldThreadPoolCommand(i).execute());
+            }
+        }
+    }
+
+    static void test1() throws Exception {
+        for (int i = 0; i < 100; i++) {
+            if (i == 3) {
+                i = 0;
+            }
+
+            HelloWorldExceptionCommand command = new HelloWorldExceptionCommand(i);
+            log.info(command.execute());
+            Thread.sleep(1000);
+        }
+    }
+
+    static void test2() throws Exception {
+        for (int i = 0; i < 100; i++) {
+            if (i == 5) {
+                i = 0;
+            }
+            HelloWorldTimeoutCommand command = new HelloWorldTimeoutCommand(i);
+            // 超时执行getFallback
+            log.info(command.execute());
+
+            Thread.sleep(1000);
+        }
+    }
+
+    public static void test3() throws Exception {
+        for (int i = 0; i < 100; i++) {
+            try {
+                if (i == 10) {
+                    i = 0;
+                    Thread.sleep(1000);
+                }
+                log.info(new HelloWorldBreakerCommand(i).execute());
+            } catch (Exception e) {
+                log.error("异常:" + e.getMessage(), e);
+            }
+        }
+    }
+
+    static void test4() throws Exception {
+        // 关闭HystrixCommand执行的超时限制,设置withExecutionTimeoutEnabled(false)
+        // withCoreSize(10)
+        for (int i = 0; i < 100; i++) {
+            Thread thread = new HelloWorldThreadPoolCommand.ThreadRunner(i);
+            thread.start();
+            Thread.sleep(500);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        //test1();
+        System.out.println("---------------------------------------------");
+        //test2();
+        System.out.println("---------------------------------------------");
+        test3();
+        System.out.println("---------------------------------------------");
+        //test4();
+    }
+}