Netflix Hystrix @DefaultProperties 注解

点击下载教程项目代码:netflix_hystrix_demo.zip

@DefaultProperties是 Hystrix 提供的一个注解,用于为类中的多个@HystrixCommand方法设置默认的配置属性。在一个包含许多服务调用方法的类中,如果每个@HystrixCommand方法都要单独设置相同的基本配置(如相同的降级方法、相同的线程池名称等),会导致代码冗余。通过@DefaultProperties可以统一设置这些默认属性,减少重复配置。

@DefaultProperties 注解

该注解用于为 Hystrix 命令指定默认参数,例如:defaultFallback = "defaultFallback"。如果我们需要为某个特定方法指定参数,可以使用 @HystrixCommand 注解。

该注解源码如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DefaultProperties {
    String groupKey() default "";

    String threadPoolKey() default "";

    HystrixProperty[] commandProperties() default {};

    HystrixProperty[] threadPoolProperties() default {};

    Class<? extends Throwable>[] ignoreExceptions() default {};

    HystrixException[] raiseHystrixExceptions() default {};

    String defaultFallback() default "";
}

属性说明:

groupKey

在 Hystrix 中,groupKey 是用于将多个相关的 @HystrixCommand 方法划分到同一个组的属性。@DefaultProperties 注解中的 groupKey 属性允许你为类中的 @HystrixCommand 方法设置一个默认的分组键。这个分组键主要用于断路器(Circuit Breaker)统计和线程池分配等方面。

当多个 @HystrixCommand 方法被划分到同一个 groupKey 组时,Hystrix 会将这些方法的相关数据(如请求次数、失败次数、成功次数等)进行聚合统计。

例如:

@Service
@DefaultProperties(groupKey = "orderServiceGroup")
public class OrderService {

    @HystrixCommand
    public Order getOrderById(Long id) {
        // 正常调用远程服务获取订单信息
    }

    @HystrixCommand
    public List<Order> getOrdersByCustomerId(Long customerId) {
        // 正常调用远程服务获取客户订单信息
    }
}

上面示例中,getOrderById 和 getOrdersByCustomerId 方法都属于 orderServiceGroup 这个分组。如果在配置线程池或者断路器等相关属性时,没有为这两个方法单独设置其他属性,它们将共享这个分组对应的默认配置。例如,它们可能共享一个默认的线程池,并且断路器的行为也会根据这个分组的配置来进行判断。

threadPoolKey

该属性用于指定一个默认的线程池键。在 Hystrix 中,线程池是基于这个键来进行分配和管理的。它允许你为类中的 @HystrixCommand 方法设置一个共享的线程池,这个线程池与threadPoolKey 相关联。

当你设置了 threadPoolKey 后,Hystrix 会根据这个键来查找或创建对应的线程池。与 groupKey 不同,threadPoolKey 更加侧重于直接控制线程池的分配。如果多个 @HystrixCommand 方法具有相同的 threadPoolKey,它们将共享这个线程池。这在你希望某些方法能够共享特定的线程资源,而不依赖于默认的基于 groupKey 的线程池分配方式时非常有用。

例如:

@Service
@DefaultProperties(threadPoolKey = "database-operations")
public class ServiceA {

    @HystrixCommand
    public void databaseWrite(Object data) {
        // 数据库写入操作
    }

    @HystrixCommand
    public String externalApiCall() {
        // 外部API调用
    }
}

上面例子中,databaseWrite 和 externalApiCall 方法都使用了 @DefaultProperties 中指定的 threadPoolKey="database-operations"。这意味着这两个方法将共享一个与 "database-operations" 关联的线程池。如果希望这两个操作能够使用不同的线程池,可以为它们分别设置不同的 threadPoolKey,比如为 databaseWrite 设置 "database-pool",为 externalApiCall 设置 "api-call-pool":

@Service
public class ServiceA {
    
    @HystrixCommand(threadPoolKey = "database-pool")
    public void databaseWrite(Object data) {
        // 数据库写入操作
    }

    @HystrixCommand(threadPoolKey = "api-call-pool")
    public String externalApiCall() {
        // 外部API调用
    }
}

注意:threadPoolKey 和 groupKey 可以一起使用来实现更精细的线程池分配和服务容错管理。通常,groupKey 用于断路器统计和高层次的分组,而 threadPoolKey 用于直接控制线程池的分配。它们可以根据实际应用场景进行灵活搭配。例如,在一个大型的微服务系统中,可能有多个服务属于同一个 groupKey(从业务功能角度划分),但其中某些服务的性能要求或资源使用特点不同,此时可以通过设置不同的 threadPoolKey 来为这些服务分配不同的线程池,以优化系统性能。

commandProperties

用于设置默认的命令属性,这些属性控制着 Hystrix 命令的行为。例如,包括执行超时时间、断路器相关属性等诸多设置。

@DefaultProperties(commandProperties = {
    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public class DemoService {
    //...
}

上面例子中,execution.isolation.thread.timeoutInMilliseconds 属性被设置为 3000 毫秒。这意味着类中的 @HystrixCommand 方法默认的超时时间是 3000 毫秒,除非某个方法自己单独设置了不同的超时时间。其他常见的命令属性还包括:

  • execution.isolation.thread.timeoutInMilliseconds:用于设置 Hystrix 命令(即被 @HystrixCommand 注解标记的方法)在独立线程(线程池隔离模式下)中执行的超时时间,单位是毫秒。

  • circuitBreaker.enabled:用于决定是否启用断路器机制。默认值是true,如果设置为false,则不会开启断路器,即使服务出现问题也不会自动切换到降级模式。

  • circuitBreaker.errorThresholdPercentage:用于设置断路器打开的错误率阈值。例如,设置为50,表示当服务调用的错误率达到 50% 时,断路器将打开。

  • circuitBreaker.sleepWindowInMilliseconds:当断路器打开后,经过这个时间间隔(单位为毫秒),会尝试进行一次半开状态的服务调用,以检查服务是否恢复正常。

threadPoolProperties

用于设置默认的线程池属性,如线程池的大小、队列大小等,以此来有效地管理 Hystrix 命令的线程资源。例如:

@DefaultProperties(threadPoolProperties = {
    @HystrixProperty(name = "coreSize", value = "10"),
    @HystrixProperty(name = "maxQueueSize", value = "100")
})
public class DemoService {
    //...
}

上面示例中,设置了线程池的核心大小为 10,最大队列大小为 100。这意味着类中的 @HystrixCommand 方法所使用的线程池默认会有 10 个核心线程,并且当任务队列中的任务数量达到 100 时,新的任务可能会根据线程池的拒绝策略进行处理。线程池属性包括:

  • coreSize:设置线程池的核心线程数量。

  • maxQueueSize:设置线程池的最大队列长度。

  • keepAliveTimeMinutes:用于设置线程池中多余线程(非核心线程)的存活时间,单位是分钟。

  • queueSizeRejectionThreshold:当队列大小达到这个阈值时,即使队列没有满,也会开始拒绝新的任务,这是一种防止队列过度填充的策略。

ignoreExceptions

用于指定一组异常类型,当 @HystrixCommand 方法抛出这些异常时,Hystrix 不会触发降级操作。这与通常情况下只要 @HystrixCommand 方法抛出异常就会触发降级的默认行为形成对比。

在某些情况下,你可能希望某些特定类型的异常不触发降级。例如,在服务调用过程中,可能会抛出一些预期的、业务相关的异常,这些异常可能是由于用户输入不符合要求或者业务规则导致的,而不是因为服务本身出现故障(如网络问题、服务过载等)。对于这些预期的业务异常,你可能希望系统正常地将异常向上传递,而不是执行降级操作。

例如:

@Service
@DefaultProperties(ignoreExceptions = {InsufficientBalanceException.class})
public class PaymentService {

    @HystrixCommand
    public PaymentResult processPayment(PaymentRequest request) {
        try {
            // 调用远程服务进行支付处理
        } catch (InsufficientBalanceException e) {
            // 余额不足异常,正常抛出,不执行降级
            throw e;
        } catch (Exception e) {
            // 其他异常,执行降级操作
            return fallbackPaymentResult();
        }
    }

    public PaymentResult fallbackPaymentResult() {
        // 降级方法,返回一个默认的支付结果
        PaymentResult result = new PaymentResult();
        result.setStatus("Payment service is currently unavailable.");
        return result;
    }
}

上面示例中,@DefaultProperties(ignoreExceptions = {InsufficientBalanceException.class}) 告诉 Hystrix,当 processPayment 方法抛出 InsufficientBalanceException 时,不要触发降级操作,而是正常地将这个异常向上抛出。只有当抛出其他类型的异常(如网络异常、服务响应超时等)时,才会执行 fallbackPaymentResult 作为降级操作。

raiseHystrixExceptions

用于控制在 Hystrix 命令执行过程中,当出现错误或者触发降级时,是否抛出 Hystrix 相关的异常。属性取值是一个 HystrixRuntimeException 类型的枚举数组。可能的取值包括HystrixRuntimeException.Failure 和 HystrixRuntimeException.Timeout 等。其中:

  • HystrixRuntimeException.Failure:当设置包含这个值时,如果 Hystrix 命令执行失败(例如,由于远程服务返回错误码、内部业务逻辑抛出异常等原因),就会抛出HystrixRuntimeException 异常,并且异常类型会标记为 Failure。这样上层调用者可以捕获这个异常并根据异常类型进行相应的处理,比如记录错误日志、进行重试等操作。

  • HystrixRuntimeException.Timeout:如果设置包含这个值,当 Hystrix 命令执行超时(超过 execution.isolation.thread.timeoutInMilliseconds 所设置的时间)时,会抛出HystrixRuntimeException 异常,异常类型标记为 Timeout。这有助于调用者区分是因为服务调用超时导致的问题,还是其他类型的故障。

例如:

@Service
@DefaultProperties(raiseHystrixExceptions = {HystrixRuntimeException.Failure, HystrixRuntimeException.Timeout},
    fallbackMethod = "defaultFallback")
public class MyService {

    @HystrixCommand
    public String callRemoteService() {
        // 正常调用远程服务的逻辑
    }

    public String defaultFallback() {
        // 降级方法
    }
}

上面示例中,@DefaultProperties 注解设置了 raiseHystrixExceptions 属性包含 HystrixRuntimeException.Failure 和 HystrixRuntimeException.Timeout。这意味着当 callRemoteService 方法在调用远程服务时,如果出现执行失败(如远程服务返回错误状态码)或者执行超时的情况,都会抛出相应类型的 HystrixRuntimeException。同时,由于还设置了 fallbackMethod 为defaultFallback,在抛出异常之前,Hystrix 会先尝试执行这个降级方法来提供一个替代的返回值。

defaultFallback

用于指定一个默认的降级方法。当类中的 @HystrixCommand 方法没有显式地设置自己的降级方法时,就会使用这个默认的降级方法。例如:

@RestController
// 配置全局Hystrix
@DefaultProperties(defaultFallback = "defaultFallback" )
public class DemoService {

    @Autowired
    private DemoService demoService;

    @GetMapping({"/"})
    @HystrixCommand // 采用默认降级方法
    public String index() {
        return demoService.getInfo();
    }

    /**
     * 全局回调方法【回退方法】
     */
    private String defaultFallback() {
        return "很抱歉,网络拥挤!";
    }

}

注意:默认回退方法不能有参数。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号