多数据源与Hystrix的冲突

1、情景描述项目要实现MySQL多数据源的主从自动切换(主库宕机自动切换从库、从库宕机切换主库)

参考博主博客如连接

2、项目在测试的时候发现的问题

项目无法成功切换数据源
1、正确的访问从库 去掉@HystrixCommand()
在这里插入图片描述
2、访问错误的从库 没去掉@HystrixCommand()
在这里插入图片描述
多数据源配置与Hystrix命令的结合出现了问题,导致数据源切换逻辑未能正确生效。

3、解决方案 在Hystrix的线程池中也能正确切换数据源,需要实现自定义的HystrixConcurrencyStrategy,并在其中覆盖wrapCallable方法来注入数据源的切换逻辑。

1、添加DelegatingContextCallable类 行前后自动管理动态数据源的选择

import java.util.concurrent.Callable;

/**
 * @title DelegatingTenantContextCallable
 * @projectName gstc2020
 * @packageName com.chinalife.gstc.commons.config
 * @createDate 2024/09/25 13:22
 * @description
 */
public final class DelegatingContextCallable<V> implements Callable<V> {

    private final Callable<V> delegate;
    private final String source;

    public DelegatingContextCallable(Callable<V> delegate, String source) {
        this.delegate = delegate;
        this.source = source;
    }

    @Override
    public V call() throws Exception {
        try {
        	// 获取数据源
            DynamicDataSourceHolder.setDynamicDataSourceKey(source);
            return delegate.call();
        } finally {
        	// 移除数据源
            DynamicDataSourceHolder.removeDynamicDataSourceKey();
        }
    }
}

2、添加 ThreadLocalAwareStrategy类 主要用于在 Hystrix 并发策略中集成 ThreadLocal 相关的逻辑,特别是与动态数据源管理相关的逻辑

import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Component
public class ThreadLocalAwareStrategy extends HystrixConcurrencyStrategy {
    private static final Log log = LogFactory.getLog(ThreadLocalAwareStrategy.class);
    private HystrixConcurrencyStrategy delegate;

    public ThreadLocalAwareStrategy() {
        try {
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof ThreadLocalAwareStrategy) {
                // Welcome to singleton hell...
                return;
            }
            HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins
                    .getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
                    .getEventNotifier();
            HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
                    .getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
                    .getPropertiesStrategy();
            this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher,
                    propertiesStrategy);
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
            HystrixPlugins.getInstance()
                    .registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        } catch (Exception e) {
            log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
        }
    }

    private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
                                                 HystrixMetricsPublisher metricsPublisher,
                                                 HystrixPropertiesStrategy propertiesStrategy) {
        if (log.isDebugEnabled()) {
            log.debug("Current Hystrix plugins configuration is ["
                    + "concurrencyStrategy [" + this.delegate + "]," + "eventNotifier ["
                    + eventNotifier + "]," + "metricPublisher [" + metricsPublisher + "],"
                    + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
            log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
        }
    }

    @Override
    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return this.delegate.getBlockingQueue(maxQueueSize);
    }

    @Override
    public <T> HystrixRequestVariable<T> getRequestVariable(
            HystrixRequestVariableLifecycle<T> rv) {
        return this.delegate.getRequestVariable(rv);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty<Integer> corePoolSize,
                                            HystrixProperty<Integer> maximumPoolSize,
                                            HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue) {
        return this.delegate.getThreadPool(threadPoolKey, corePoolSize,
                maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        return this.delegate.wrapCallable(new DelegatingContextCallable<>(callable, DynamicDataSourceHolder.getDynamicDataSourceKey()));
    }
}

这样就能实现Hystrix注解与多数据源产生线程冲突了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值