zoukankan      html  css  js  c++  java
  • Spring 中的多数据源配置

    Spring的多数据源配置中会用到AbstractRoutingDataSource,从名字也可以看出他的作用,抽象的带路由的数据源,源码的说明如下:

    * Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}
     * calls to one of various target DataSources based on a lookup key. The latter is usually
     * (but not necessarily) determined through some thread-bound transaction context.

    类的声明如下:

    public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
    ......
    }

    那他是如何做到多数据源访问的呢,跟下代码,AbstractRoutingDataSource的getConnection方法:

    @Override
        public Connection getConnection() throws SQLException {
            return determineTargetDataSource().getConnection();
        }
    determineTargetDataSource方法:
    /**
         * Retrieve the current target DataSource. Determines the
         * {@link #determineCurrentLookupKey() current lookup key}, performs
         * a lookup in the {@link #setTargetDataSources targetDataSources} map,
         * falls back to the specified
         * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
         * @see #determineCurrentLookupKey()
         */
        protected DataSource determineTargetDataSource() {
            Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
            Object lookupKey = determineCurrentLookupKey();//获取key
            DataSource dataSource = this.resolvedDataSources.get(lookupKey);//根据key获取真正的数据源,当然前提是resolvedDataSources有值,这也是子类实现中做的事情
            if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
                dataSource = this.resolvedDefaultDataSource;
            }
            if (dataSource == null) {
                throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
            }
            return dataSource;
        }
    determineCurrentLookupKey方法:
        /**
         * Determine the current lookup key. This will typically be
         * implemented to check a thread-bound transaction context.
         * <p>Allows for arbitrary keys. The returned key needs
         * to match the stored lookup key type, as resolved by the
         * {@link #resolveSpecifiedLookupKey} method.
         */
        @Nullable
        protected abstract Object determineCurrentLookupKey();

    注意这是一个抽象方法,是留给子类实现具体的选择数据源的方法,从方法声明中知道返回的是一个的lookupkey,即数据源的key。

    那子类应该如何写呢,以若依框架中的多数据源配置为例:

    package com.ruoyi.framework.datasource;
    
    import java.util.Map;
    import javax.sql.DataSource;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    /**
     * 动态数据源:继承在AbstractRoutingDataSource,并设置了父类的targetDataSources,决定使用数据源的key
     * @author ruoyi
     */
    public class DynamicDataSource extends AbstractRoutingDataSource
    {
        public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
        {
            super.setDefaultTargetDataSource(defaultTargetDataSource);
         //设置父类的targetDataSources,供获取connection时选择使用哪一个数据源
    super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } @Override
        //决定使用的数据源的key
    protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceType(); } }
    package com.ruoyi.framework.datasource;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 数据源切换处理
     * 
     * @author ruoyi
     */
    public class DynamicDataSourceContextHolder
    {
        public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
    
        /**
         * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
         *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
         */
        private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    
        /**
         * 设置数据源的变量
         */
        public static void setDataSourceType(String dsType)
        {
            log.info("切换到{}数据源", dsType);
            CONTEXT_HOLDER.set(dsType);
        }
    
        /**
         * 获得数据源的变量
         */
        public static String getDataSourceType()
        {
            return CONTEXT_HOLDER.get();
        }
    
        /**
         * 清空数据源变量
         */
        public static void clearDataSourceType()
        {
            CONTEXT_HOLDER.remove();
        }
    }

    此类借助于ThreadLocal用于设置和获取具体的数据源的key。

  • 相关阅读:
    结对项目黄金点游戏(邓乐&曾亮)
    软件工程个人项目:一个能自动生成小学四则运算的程序
    IE7下面zindex失效的问题
    参加一战到底有感
    Javascript中的prototype
    浏览器的页面渲染
    使用document.domain实现ajax跨子域
    PHP模拟http请求
    六天带你了解活动营销之第一天营销活动形式多样化
    jQuery源码学习第一天jQuery框架学习
  • 原文地址:https://www.cnblogs.com/silenceshining/p/14284800.html
Copyright © 2011-2022 走看看