自定义HystrixConcurrencyStrategy

背景:项目中采用了Feigin + Hystrix 实现RPC 熔断处理,当使用到了 Hystrix 线程隔离机制时,由于业务中对于 Feigin 调用请求拦截器中统一添加 Token 到请求 Header中,由于多线程的缘故导致拦截器无法正常获取到ThreadLocal中设置的参数。

Tips: 解决ThreadLocal传值和线程池可见性方案有很多种,今天重点介绍下 Hystrix 提供的解决方案。

一、自定义实现HystrixConcurrencyStrategy 和 自定义CallableWrapper 包装器

package com.github.ext;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;

/**
 * 熔断器并发处理策略
 */
public class HystrixConcurrencyStrategyExtension extends HystrixConcurrencyStrategy {
    protected final static ThreadLocal> threadLocal = new ThreadLocal>() {
        @Override
        protected Map initialValue() {
            return new HashMap<>();
        }
    };


    /**
     * 设置属性信息到上下文
     *
     * @param name  属性名称(不能为空)
     * @param value 属性值(不能为空)
     */
    public static void setAttribute(String name, Object value) {
        Objects.requireNonNull(name, "`name` cannot be null");
        Objects.requireNonNull(value, "`value` cannot be null");
        threadLocal.get().putIfAbsent(name, value);
    }

    /**
     * 获取属性值
     *
     * @param name 属性名称
     * @return
     */
    public static  Optional getAttribute(String name) {
        Object value = threadLocal.get().get(name);
        return (Optional) Optional.ofNullable(value);
    }

    /**
     * 清除上下文信息
     */
    public static void remove() {
        threadLocal.remove();
    }

    /**
     * 包装Callable处理器
     *
     * @return
     */
    @Override
    public  Callable wrapCallable(Callable callable) {
        return new CallableWrapper(callable);
    }

    /**
     * 实现自定义Callable包装器
     * @param 
     */
    public static class CallableWrapper implements Callable {

        private final Callable delegate;
        private final Map attributes;

        public CallableWrapper(Callable callable) {
            this.delegate = callable;
            this.attributes = HystrixConcurrencyStrategyExtension.threadLocal.get();
        }

        @Override
        public T call() throws Exception {
            try {
                HystrixConcurrencyStrategyExtension.threadLocal.set(attributes);
                return delegate.call();
            } finally {
                HystrixConcurrencyStrategyExtension.remove();
            }
        }
    }
}

二、将HystrixConcurrencyStrategyExtension注册到 Hystrix 即可。

方式一:通过 Java SPI 扩展机制实现自动注册

在工程 resources/目录下创建目录:META-INF/services/
创建文件:com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy 并将自定义的扩展类名称写入到文件即可,
com.github.ext.HystrixConcurrencyStrategyExtension

方式二:通过Hystrix 提供的编程式 API 来实现注册

HystrixPlugins.reset();
HystrixPlugins.getInstance().registerConcurrencyStrategy(new HystrixConcurrencyStrategyExtension());

测试用例:

//获取当前 Hystrix 并发访问策略
HystrixPlugins.getInstance().getConcurrencyStrategy();
//设置传递参数
HystrixConcurrencyStrategyExtension.setAttribute("token", "HelloWorld!!!");
assert HystrixConcurrencyStrategyExtension.getAttribute("token").equals("HelloWorld!!!");

官方文档:https://github.com/Netflix/Hystrix/wiki/Plugins

你可能感兴趣的:(java,Hystrix,java)