在Spring Cloud Feign的框架下,远程调用一般需要引入Hystrix来熔断限流。hystrix默认是以线程池进行资源隔离,也就是说当一个线程准备发起Feign调用时,真正进行网络请求的动作是在hystrix中的线程池中进行的。如果此时我们想要编写feign拦截器做一些自定义的事情,那么将无法获取调用线程中的数据。
比如,在拦截器中我们想把每次请求的用户信息带上,如果直接采用ThreadLocal来实现是行不通的,ThreadLocal无法做到将数据从调用线程传到线程池中。
hystrix提供了一种解决方案HystrixRequestVariableDefault
这里封装了一个小工具可以实现数据传递的功能。
public class TestController { @Resource private PeopleClient peopleClient; @GetMapping("/getMap") public Response<List<Object>> getAll(@RequestParam("name") String name) { // 设置需要传递的数据 UserTraceContext.initializeContext(); UserSession session = new UserSession(); session.setName(name); UserTraceContext.setData(session); List<Object> list = new ArrayList<>(); list.add(peopleClient.getPeopleEx()); Object data = UserTraceContext.getData(); log.info("Who get map = {}", ((UserSession)data).getName()); return new Response(list); } @GetMapping("/getPeopleEx") public Response<People> getPeopleEx() { return new Response<People>(new People()); } }
@Component @Slf4j public class BizInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { // 拦截器中可以获取数据 log.info("**********this is a biz interceptor******"); Object data = UserTraceContext.getData(); log.info("Who get map = {}", ((UserSession)data).getName()); // 打印为null log.info("threadLocal = {}", CacheManager.threadLocal.get()); log.info("**********this is a biz interceptor******"); } }
代码使用了一个封装的小工具,源码参见 https://github.com/markytsai/context-util