Skip to content

添加@HystrixCommand导致ThreadLocal失效或null #6

@dengly

Description

@dengly

在项目里使用了@HystrixCommand会导致ThreadLocal null。而我们使用的是THREAD隔离策略。网上搜索也知道了原因,可以参考这篇博文

但是最终他的处理办法不推荐,在调试和看spring-security-coreorg.springframework.cloud.netflix.hystrix.security.SecurityContextConcurrencyStrategyorg.springframework.security.concurrent.DelegatingSecurityContextCallable给了我们解决办法。

添加以下类即可解决问题

@Configuration
public class ApiHystrixConfig {

    @Autowired(required = false)
    private HystrixConcurrencyStrategy existingConcurrencyStrategy;


    @PostConstruct
    public void init() {
        // Keeps references of existing Hystrix plugins.   保留现有Hystrix插件。
        HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
                .getEventNotifier();
        HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
                .getMetricsPublisher();
        HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
                .getPropertiesStrategy();
        HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance()
                .getCommandExecutionHook();

        HystrixPlugins.reset();

        // Registers existing plugins excepts the Concurrent Strategy plugin. 注册除Concurrent Strategy插件之外的现有插件。
        HystrixPlugins.getInstance().registerConcurrencyStrategy(
                new ApiContextConcurrencyStrategy(existingConcurrencyStrategy));
        HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
        HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
        HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
    }

    class ApiContextConcurrencyStrategy extends HystrixConcurrencyStrategy {
        private HystrixConcurrencyStrategy existingConcurrencyStrategy;

        public ApiContextConcurrencyStrategy(HystrixConcurrencyStrategy existingConcurrencyStrategy) {
            this.existingConcurrencyStrategy = existingConcurrencyStrategy;
        }

        @Override
        public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
            return existingConcurrencyStrategy != null
                    ? existingConcurrencyStrategy.getBlockingQueue(maxQueueSize)
                    : super.getBlockingQueue(maxQueueSize);
        }

        @Override
        public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
            return existingConcurrencyStrategy != null
                    ? existingConcurrencyStrategy.getRequestVariable(rv)
                    : super.getRequestVariable(rv);
        }

        @Override
        public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                                HystrixProperty<Integer> corePoolSize,
                                                HystrixProperty<Integer> maximumPoolSize,
                                                HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
                                                BlockingQueue<Runnable> workQueue) {
            return existingConcurrencyStrategy != null
                    ? existingConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize,
                    maximumPoolSize, keepAliveTime, unit, workQueue)
                    : super.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
                    keepAliveTime, unit, workQueue);
        }

        @Override
        public <T> Callable<T> wrapCallable(Callable<T> callable) {
            return existingConcurrencyStrategy != null
                    ? existingConcurrencyStrategy
                    .wrapCallable(new ApiContextCallable<T>(callable))
                    : super.wrapCallable(new ApiContextCallable<T>(callable));
        }
    }

    class ApiContextCallable<V> implements Callable<V> {
        private final Callable<V> delegate;
        private final Object delegateObject;
        private Object originalObject;

        public ApiContextCallable(Callable<V> delegate, Object delegateObject) {
            Assert.notNull(delegate, "delegate cannot be null");
            this.delegate = delegate;
            this.delegateObject = delegateObject;
        }

        public ApiContextCallable(Callable<V> delegate) {
            this(delegate, TokenContext.get());
        }

        public V call() throws Exception {
            try {
                // 重点在这里 TokenContext 是我自己的上下文
                // TokenContext.get() 和 TokenContext.set() 都是对自己的ThreadLocal操作
                this.originalObject = TokenContext.get();
                TokenContext.set(this.delegateObject);
                V reV = this.delegate.call();
                return reV;
            } finally {
                TokenContext.set(this.originalObject);
                this.originalObject = null;
            }

        }

        public String toString() {
            return this.delegate.toString();
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions