如何在spring框架中解决多数据源的问题

 我来答
huanglenzhi
2015-01-08 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
采纳数:117538 获赞数:517193
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。

向TA提问 私信TA
展开全部

  问题的解决

  (一)            采用Decorator设计模式

  要解决这个问题,我的思路锁定在了这个dataSource上了。如果sessionFactory指向的dataSource可以根据客户的需求去连接客户所需要的真正的数据源,即提供动态切换数据源的功能,那么问题就解决了。那么我们怎么做呢?去修改那些我们要使用的dataSource源码吗?这显然不是一个好的方案,我们希望我们的修改与原dataSource代码是分离的。根据以上的分析,使用GoF设计模式中的Decorator模式(装饰者模式)应当是我们可以选择的最佳方案。


  什么是“Decorator模式”?简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,设计一个Decorator套在原有代码外面。当我们使用Decorator的时候与原类完全一样,当Decorator的某些功能却已经修改为了我们需要修改的功能。Decorator模式的结构如图。


  我们本来需要修改图中所有具体的Component类的一些功能,但却并不是去直接修改它们的代码,而是在它们的外面增加一个Decorator。Decorator与具体的Component类都是继承的AbstractComponent,因此它长得和具体的Component类一样,也就是说我们在使用Decorator的时候就如同在使用ConcreteComponentA或者ConcreteComponentB一样,甚至那些使用ConcreteComponentA或者ConcreteComponentB的客户程序都不知道它们用的类已经改为了Decorator,但是Decorator已经对具体的Component类的部分方法进行了修改,执行这些方法的结果已经不同了。


  (二)            设计MultiDataSource类

  现在回到我们的问题,我们需要对dataSource的功能进行变更,但又不希望修改dataSource中的任何代码。我这里指的dataSource是所有实现javax.sql.DataSource接口的类,我们常用的包括apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等,这些类我们不可能修改它们本身,更不可能对它们一个个地修改以实现动态分配数据源的功能,同时,我们又希望使用dataSource的sessionFactory根本就感觉不到这样的变化。Decorator模式就正是解决这个问题的设计模式。


  首先写一个Decorator类,我取名叫MultiDataSource,通过它来动态切换数据源。同时在配置文件中将sessionFactory的dataSource属性由原来的某个具体的dataSource改为MultiDataSource。如图:


  对比原Decorator模式,AbstractComponent是一个抽象类,但在这里我们可以将这个抽象类用接口来代替,即DataSource接口,而ConcreteComponent就是那些DataSource的实现类,如BasicDataSource、JndiObjectFactoryBean等。MultiDataSource封装了具体的dataSource,并实现了数据源动态切换:


  java 代码

  1.public class MultiDataSource implements DataSource {

  2.    private DataSource dataSource = null;

  3.public MultiDataSource(DataSource dataSource){

  4.        this.dataSource = dataSource;

  5.    }

  6.    /* (non-Javadoc)

  7.     * @see javax.sql.DataSource#getConnection()

  8.     */

  9.    public Connection getConnection() throws SQLException {

  10.        return getDataSource().getConnection();

  11.    }

  12.    //其它DataSource接口应当实现的方法

  13.

  14.    public DataSource getDataSource(){

  15.        return this.dataSource;

  16.        }

  17.    }

  18.    public void setDataSource(DataSource dataSource) {

  19.        this.dataSource = dataSource;

  20.    }

  21.}

  客户在发出请求的时候,将dataSourceName放到request中,然后把request中的数据源名通过调用new MultiDataSource(dataSource)时可以告诉MultiDataSource客户需要的数据源,就可以实现动态切换数据源了。但细心的朋友会发现这在单例的情况下就是问题的,因为MultiDataSource在系统中只有一个对象,它的实例变量dataSource也只有一个,就如同一个静态变量一般。正因为如此,单例模式让许多设计模式都不得不需要更改,这将在我的《“单例”更改了我们的设计模式》中详细讨论。那么,我们在单例模式下如何设计呢?


  (三)            单例模式下的MultiDataSource

  在单例模式下,由于我们在每次调用MultiDataSource的方法的时候,dataSource都可能是不同的,所以我们不能将dataSource放在实例变量dataSource中,最简单的方式就是在方法getDataSource()中增加参数,告诉MultiDataSource我到底调用的是哪个dataSource:


  java 代码

  1.public DataSource getDataSource(String dataSourceName){

  2.        log.debug("dataSourceName:"+dataSourceName);

  3.        try{

  4.            if(dataSourceName==null||dataSourceName.equals("")){

  5.                return this.dataSource;

  6.            }

  7.            return (DataSource)this.applicationContext.getBean(dataSourceName);

  8.        }catch(NoSuchBeanDefinitionException ex){

  9.            throw new DaoException("There is not the dataSource

  10.        }

  11.    }

  值得一提的是,我需要的数据源已经都在spring的配置文件中注册,dataSourceName就是其对应的id。


  xml 代码

  1.<bean id="dataSource1"

  2.    class="org.apache.commons.dbcp.BasicDataSource">

  3.    <property name="driverClassName">

  4.        <value>oracle.jdbc.driver.OracleDrivervalue>

  5.    property>

  6.    ......

  7.bean>

  8.<bean id="dataSource2"

  9.    class="org.apache.commons.dbcp.BasicDataSource">

  10.    <property name="driverClassName">

  11.        <value>oracle.jdbc.driver.OracleDrivervalue>

  12.    property>

  13.    ......

  14.bean>

  为了得到spring的ApplicationContext,MultiDataSource类必须实现接口org.springframework.context.ApplicationContextAware,并且实现方法:


  java 代码

  1.private ApplicationContext applicationContext = null;

  2.public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

  3.        this.applicationContext = applicationContext;

  4.    }

  如此这样,我就可以通过this.applicationContext.getBean(dataSourceName)得到dataSource了。

推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式