Spring 动态数据源原理剖析

数据源是在什么时候注入的

ibatis中  Dao实现类都需要继承SqlMapClientDaoSupport,如下图中,SqlMapClientDaoSupport 中注入的  DataSource

 

spring留下的拓展点

//key和数据库连接的映射关系

private Map<Object, Object> targetDataSources;

// 标识默认的连接

private Object defaultTargetDataSource;

// 这个数据结构是通过targetDataSources构建而来,存储结构也是数据库标识和数据源的映射关系

private Map<Object, DataSource> resolvedDataSources;

 

 

XML 配置

<bean id="dataSource" class="com.xxx.DynamicDataSource">

    <property name="targetDataSources">

        <map key-type="java.lang.String">

            <entry key="master" value-ref="masterDataSource" />

            <entry key="test" value-ref="testDataSource" />

            <entry key="official" value-ref="officialDataSource" />

        </map>

    </property>

    <property name="defaultTargetDataSource" ref="masterDataSource" />

</bean>

com.xxx.DynamicDataSource是继承了AbstractRoutingDataSource类

而AbstractRoutingDataSource实现了InitializingBean接口,并实现了afterPropertiesSet方法。afterPropertiesSet方法是初始化bean的时候执行,可以针对某个具体的bean进行执行。

@Override

public void afterPropertiesSet() {

    if (this.targetDataSources == null) {

        throw new IllegalArgumentException("Property 'targetDataSources' is required");

    }

    this.resolvedDataSources = new HashMap<Object, DataSource> (this.targetDataSources.size()); //初始化resolvedDataSources

        //循环targetDataSources,并添加到resolvedDataSources中

    for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {

        Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());

        DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());

        this.resolvedDataSources.put(lookupKey, dataSource);

    }

        //如果默认数据源不为空则指定对应数据源

    if (this.defaultTargetDataSource != null) {

        this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);

    }

}

这里的targetDataSources属性(map)是存储将要切换的多数据源bean信息。

而如果数据源在数据库中,则需要重写方法determineCurrentLookupKey(),因为数据源bean是动态生成的,然后需要添加到targetDataSources中,此时需要调用afterPropertiesSet()方法,来通知spring有bean更新。

因为此抽象类中都是引用resolvedDataSources属性,所以在此方法中将targetDataSources属性的键值信息存储到resolvedDataSources属性中,以便后续调用。

3.连接数据库的getConnection()方法,调用的是determineTargetDataSource()方法,来创建连接。

@Override

public Connection getConnection() throws SQLException {

    return determineTargetDataSource().getConnection();

}

  

@Override

public Connection getConnection(String username, String password) throws SQLException {

    return determineTargetDataSource().getConnection(username, password);

}

而determineTargetDataSource()方法是决定spring容器连接那个数据源

protected DataSource determineTargetDataSource() {

    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");

    //具体选择哪个数据源

    Object lookupKey = determineCurrentLookupKey();

    DataSource dataSource = this.resolvedDataSources.get(lookupKey);

    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()方法来决定的,此方法是抽象方法,需要我们继承AbstractRoutingDataSource抽象类来重写此方法。该方法返回一个key,该key是bean中的beanName,并赋值给lookupKey,由此key可以通过resolvedDataSources属性的键来获取对应的DataSource值,从而达到数据源切换的功能。

protected abstract Object determineCurrentLookupKey();

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值