前言
Hystrix提供了基于信号量和线程两种隔离模式,通过在Hystrix基础章节中已经验证过,通过
@HystrixCommand注解的方法体将在新的线程中执行,这样会带来些什么意想不到的意外呢,先来看一个示例:
1、定义一个webapi,通过
RequestContextHolder设定一个当前线程的上下文:
@GetMapping(value = "/getServerInfo/{serviceName}")
public String getServer1Info(@PathVariable(value = "serviceName") String serviceName) {
LOGGER.info("当前线程ID:" + Thread.currentThread().getId() + "当前线程Name" + Thread.currentThread().getName());
RequestContextHolder.currentRequestAttributes().setAttribute("context", "main-thread-context", SCOPE_REQUEST);
return consumeService.getServerInfo(serviceName);
}
2、在
@HystrixCommand注解的方法中再次通过RequestContextHolder获取当前上下文设定的value值:
@Override
@HystrixCommand(fallbackMethod = "getServerInfoFallback",
commandProperties = {@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")},
commandKey = "cust2GetServerInfo",
threadPoolKey = "cust2ThreadPool",
groupKey = "cust2")
public String getServerInfo(String serviceName) {
LOGGER.info(RibbonFilterContextHolder.getCurrentContext().get("TAG"));
LOGGER.info(RequestContextHolder.currentRequestAttributes().getAttribute("context", SCOPE_REQUEST).toString());
//如果是service1则需要添加http认证头,service1暂时添加了认证机制;反之service2不需要认证直接发出请求即可
if ("service1".equals(serviceName)) {
HttpEntity<String> requestEntity = new HttpEntity<String>(getHeaders());
ResponseEntity<String> responseEntity = restTemplate.exchange("http://" + serviceName + "/getServerInfo?userName=shuaishuai", HttpMethod.GET, requestEntity, String.class);
return responseEntity.getBody();
} else
return restTemplate.getForObject("http://" + serviceName + "/getServerInfo?userName=shuaishuai", String.class);
}
public String getServerInfoFallback(String serviceName, Throwable e) {
if (e != null) {
LOGGER.error(e.getMessage());
}
return "Maybe the server named " + serviceName + " is not normal running";
}
3、启动服务请求1中定义的API:
可以看到上图中上下文的赋值与取值在不同的线程中执行,TAG信息被正常获取,而
RequestContextHolder设定的上线文信息获取失败,并进入回退方法并打印出了对应的异常信息,首先来看下为何TAG信息被正常获取,在
RibbonFilterContextHolder中定义变量如下
而在RequestContextHolder中变量定义如下
其区别在于是采用
ThreadLocal与
InheritableThreadLocal的差异,
InheritableThreadLocal能够在子线程中继续传播父线程的上线文,而ThreadLocal只能在保存在当前线程中,但事实上我们不可能所有的应用均采用
InheritableThreadLocal,尽管他是一个不错的选择,但如何让ThreadLocal也实现在Hystrix应用场景下实现线程上下文的传播呢。这就是本章的重点了。
本章概要
1、资料搜索;
2、源码分析;
3、扩展HystrixConcurrencyStrategy解决前言中的意外;
4、提高HystrixConcurrencyStrategy包装扩展性;
资料搜索