注解配置Hystrix (原文:https://blog.csdn.net/chenxyz707/article/details/80913725?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param)

Hystrix也支持以注解的形式配置。通过@HystrixCommand注解的fallbackMethod属性指定降级方法。groupKeycommandKey默认为方法名

(当然threadPoolKey不指定时,默认和groupKey一致,所以也是方法名),也可以指定这三个key值,配置文件通过groupKey,commandKey,threadPoolKey使用恰当的配置。

commandPropertiesthreadPoolProperties是通过@HystrixPropertyname value键值对进行配置。

@Component
public class UserAnnotationCommand {

    @Autowired
    @Qualifier("lbRestTemplate")
    RestTemplate lbRestTemplate;

    @HystrixCommand(fallbackMethod = "timeoutFallback", threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "20"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "20")
    }, commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "8000")
    })
    public String timeout() {
        return lbRestTemplate.getForObject("http://user-service/user/timeout", String.class);
    }

    public String timeoutFallback() {
        return "timeout 降级";
    }


    @HystrixCommand(fallbackMethod = "exceptionFallback", threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "20"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "20")
    }, commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })
    public String exception() {
        return lbRestTemplate.getForObject("http://user-service/user/exception", String.class);
    }

    public String exceptionFallback() {
        return "exception 降级";
    }
}

 

查看com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect源码,我们可以看到@HystrixCommand注解配置的方式是使用了AOP动态的生成了一个HystrixInvokable对象,通过调用HystrixInvokable的方法实现了HystrixCommand的功能。

// 使用AOP让注解的@HystrixCommand生效
@Aspect
public class HystrixCommandAspect {
    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")
    public void hystrixCommandAnnotationPointcut() {
    }
    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
    public void hystrixCollapserAnnotationPointcut() {
    }

    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getMethodFromTarget(joinPoint);
        /***省略***/
        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();

        Object result;
        try {
            if (!metaHolder.isObservable()) {
                result = CommandExecutor.execute(invokable, executionType, metaHolder);
            } else {
                result = executeObservable(invokable, executionType, metaHolder);
            }
        } catch (HystrixBadRequestException e) {
            throw e.getCause() != null ? e.getCause() : e;
        } catch (HystrixRuntimeException e) {
            throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
        }
        return result;
    }
}

 

同样的为了测试这个配置是否生效我们新增接口:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserAnnotationCommand userAnnotationCommand;

    @RequestMapping("/command/annotation/timeout")
    public String commandAnnotationTimeout() {
        return userAnnotationCommand.timeout();
    }

    @RequestMapping("/command/annotation/exception")
    public String commandAnnotationException() {
        return userAnnotationCommand.exception();
    }
}

 

 

和FeignClient集成

在SpringCloud中Hystrix和Feign的集成十分方便。在客户端我们需要使用@EnableCircuitBreaker启用熔断机制。

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(defaultConfiguration = FeignClientsConfiguration.class)
@EnableCircuitBreaker
public class WebApplicationStarter {

    public static void main(String[] args) {
        SpringApplication.run(WebApplicationStarter.class, args);
    }
}

同时application.yml配置文件中开启Hystrix,并进行Hystrix配置。

# 开启熔断机制
feign:
  hystrix:
    enabled: true

ribbon:
  # 开启eureka与ribbon的集成
  eureka:
    enabled: true
  # 暂不开启熔断机制
  hystrix:
    enabled: false
  # 配置ribbon默认的超时时间
  ConnectTimeout: 20000
  ReadTimeout: 20000
  # 是否开启重试
  OkToRetryOnAllOperations: true
  # 重试的时候实例切换次数
  MaxAutoRetriesNextServer: 3
  # 每个实例重试次数
  MaxAutoRetries: 2

## hystrix相关配置
## hystrix默认会读取classpath下的config.properties文件,application会覆盖config.properties中的属性
hystrix:
  threadpool:
    # 指定服务的配置
    user-service:
      coreSize: 20
      maxQueueSize: 200
      queueSizeRejectionThreshold: 3
    # userThreadPool是UserTimeOutCommand中配置的threadPoolKey
    userThreadPool:
      coreSize: 20
      maxQueueSize: 20
      queueSizeRejectionThreshold: 3
    # 这是默认的配置
    default:
      coreSize: 10
      maxQueueSize: 200
      queueSizeRejectionThreshold: 2
  command:
    # 指定feign客户端中具体的方法
    UserService#timeout():
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 20000
    userCommandKey:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 15000
    # 这是默认的配置
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          strategy: THREAD
          thread:
            timeoutInMilliseconds: 15000
            interruptOnTimeout: true
            interruptOnFutureCancel: false
          semaphore:
            maxConcurrentRequests: 2
      fallback:
        enabled: true
        isolation:
          semaphore:
            maxConcurrentRequests: 10
      circuitBreaker:
        enabled: true
        forceOpen: false
        forceClosed: false
        requestVolumeThreshold: 4
        errorThresholdPercentage: 50
        sleepWindowInMilliseconds: 10000
      metrics:
        rollingStats:
          timeInMilliseconds: 5000
          numBuckets: 10
        rollingPercentile:
          enabled: true
          timeInMilliseconds: 60000
          numBuckets: 6
          bucketSize: 100
        healthSnapshot:
          intervalInMilliseconds: 500

这里为了测试超时接口,所以Ribbon配置的超时时间(20s)大于接口的返回时间(10s),否则在Ribbon超时后将自动重试,直到超过Hystrix的超时时间时返回降级信息。在实际中,Hystrix的超时时间应该大于Ribbon的超时时间*Ribbon的重试次数。

如果项目中config.propertiesapplication.yml文件中都有Hystrix的配置,对于同一配置项,application.yml中的属性会覆盖config.properties中的属性值。当然使用Java API和注解方式也是优先读取application.yml的配置。

在这个配置中我们甚至可以指定FeignClient中的某一方法的Hystrix配置。比如上面的配置文件中我们定义了UserServicetimeout()方法的超时时间为20s。
新增Feign客户端和降级类,降级类必须实现对应的Feign客户端。

@FeignClient(name="user-service", fallback = UserServiceFallback.class)
public interface UserService {

    @RequestMapping(value = "/user/timeout", method = RequestMethod.GET)
    public String timeout();

    @RequestMapping(value = "/user/exception", method = RequestMethod.GET)
    public String exception();
}
@Component
public class UserServiceFallback implements UserService {

    @Override
    public String timeout() {
        return "timeout 降级";
    }

    @Override
    public String exception() {
        return "exception 降级";
    }
}

 

 

 
posted on 2020-09-24 14:53  lshan  阅读(898)  评论(0编辑  收藏  举报