简化spring数据源配置:创建自定义datasource工厂类

本文介绍了一种自定义的DataSourceFactoryBean,该工厂类可以根据jndi属性自动选择从JNDI获取数据源还是使用jdbc驱动创建。通过这种方式,可以简化Spring应用程序在部署时的数据源配置,只需修改一个属性即可切换数据源获取方式。

最近在做项目,开发时是通过driver创建datasource的,配置如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${dataSource.driverClassName}" />
    <property name="url" value="${dataSource.url}" />
    <property name="username" value="${dataSource.username}" />
    <property name="password" value="${dataSource.password}" />
</bean>

实施时是通过jndi查找得到datasource,配置如下:
<bean  id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property  name="jndiName" value="${dataSource.jndiName}" />
</bean>

其中属性文件是通过propertyConfigurer导入的:
<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    dependency-check="none">
    <property name="fileEncoding" value="UTF-8" />
    <property name="locations">
        <list>
            <value>classpath:spring-app.properties</value>
        </list>
    </property>
</bean>

文件的内容如下:

dataSource.jndiName=jdbc/myDataSource
dataSource.driverClassName=oracle.jdbc.driver.OracleDriver
dataSource.url=jdbc:oracle:thin:@localhost:1521:myServId
dataSource.username=myUser
dataSource.password=myPassword

采用上面这种方式,在每次部署的时候都要修改
applicationContext.xml的dataSource配置,有点麻烦

通过学习 JndiObjectFactoryBean 的代码,自己写了一个数据源的工厂类:

// ===================================================================
package laochake.spring.datasource;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.util.StringUtils;

/**
 * 数据源工厂bean,通过 jndi 属性判断是从jndi取得数据源还是用jdbc驱动创建数据源<br>
 * 设计此类的目的是简化部署时的配置,即只同过设置定jndi的值就可以自动切换数据源的获取方式
 * @author laochake
 * @since  2007-12-13 下午01:26:46
 */
public class DataSourceFactoryBean implements FactoryBean,InitializingBean {
  
 /**缓存数据源对象*/
 private DataSource dataSource;
 /**是否jndi数据源*/
 private boolean jndi;
 /**数据源的名字(如果是jndi数据源)*/
 private String jndiName;
 /**jdbc驱动类(非jndi的情况)*/
 private String driverClassName;
 /**数据库的url(非jndi的情况)*/
 private String url;
 /**用户名(非jndi的情况)*/
 private String username;
 /**密码(非jndi的情况)*/
 private String password;
 
 //TODO:此处省略了属性的set方法
 
 /**
  * 初始化
  * @author laochake
  * @since  2007-12-13 下午01:48:03
  * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
  */
 public void afterPropertiesSet() throws Exception {
  if(this.isJndi()){
   if (!StringUtils.hasText(this.jndiName)) {
    throw new IllegalArgumentException("jndiName is required");
   }
  }else{
   if (!StringUtils.hasText(this.driverClassName)) {
    throw new IllegalArgumentException("driverClassName is required");
   }
   if (!StringUtils.hasText(this.url)) {
    throw new IllegalArgumentException("url is required");
   }
   if (!StringUtils.hasText(this.username)) {
    throw new IllegalArgumentException("username is required");
   }
   if (!StringUtils.hasText(this.password)) {
    throw new IllegalArgumentException("password is required");
   }
  }
  //在初始化时就创建数据源
  this.createDataSource();
 }

 /**
  * 实现 FactoryBean 的方法,取得对象
  * @author laochake
  * @since  2007-12-13 下午01:33:35
  * @see org.springframework.beans.factory.FactoryBean#getObject()
  */
 public Object getObject() {
  DataSource ds = this.createDataSource();
  return ds;
 }
 
 /**
  * 创建数据源对象,并保存到 this.dataSource属性
  * @author laochake
  * @since  2007-12-13 下午01:46:44
  * @return
  */
 protected DataSource createDataSource(){
  DataSource ds = this.dataSource;
  if(ds==null){
   try{
    if(this.isJndi()){
     ds = new JndiDataSourceSupport().lookupDataSource(this.jndiName);
    }else{
     ds=new DriverManagerDataSource(driverClassName, url, username, password);
    }
   }catch(Throwable err){
    throw new RuntimeException(err);
   }
  }
  this.dataSource=ds;
  return ds;
 }

 /**
  * 实现 FactoryBean 的方法,取得工厂创建的对象类型
  * @author laochake
  * @since  2007-12-13 下午01:42:57
  * @see org.springframework.beans.factory.FactoryBean#getObjectType()
  */
 public Class getObjectType() {
  return javax.sql.DataSource.class;
 }
 
 /**
  * 实现 FactoryBean 的方法,是否单例模式(始终返回true)
  * @author laochake
  * @since  2007-12-13 下午01:43:29
  * @see org.springframework.beans.factory.FactoryBean#isSingleton()
  */
 public boolean isSingleton() {
  return true;
 }

 /**
  * jndi数据源查找类(内部私有类)
  * @author laochake
  * @since  2007-12-13 下午01:49:09
  */
 private class JndiDataSourceSupport extends JndiLocatorSupport{
  public DataSource lookupDataSource(String jndiName) throws NamingException{
   return (DataSource)super.lookup(jndiName, javax.sql.DataSource.class);
  }
 }
 
}
//===================================================================================

使用以上定义类,新的dataSource定义方式如下:
<bean id="dataSource" class="com.gdcn.spring.datasource.DataSourceFactoryBean">
    <description><![CDATA[ 数据源定义 ]]></description>
    <property name="jndi" value="${dataSource.IS_JNDI}" />
    <property name="jndiName" value="${dataSource.jndiName}" />
    <property name="driverClassName" value="${dataSource.driverClassName}" />
    <property name="url" value="${dataSource.url}" />
    <property name="username" value="${dataSource.username}" />
    <property name="password" value="${dataSource.password}" />
</bean>
新的 spring-app.properties 文件内容如下:

dataSource.IS_JNDI=false
dataSource.jndiName=jdbc/myDataSource
dataSource.driverClassName=oracle.jdbc.driver.OracleDriver
dataSource.url=jdbc:oracle:thin:@localhost:1521:myServId
dataSource.username=myUser
dataSource.password=myPassword

在部署应用时,如果使用jdbc驱动创建数据源,则IS_JNDI=false
如果使用jndi查找得到数据源,则IS_JNDI=true

可见第二种方式的配置简单了很多,只通过修改dataSource.IS_JNDI就能实现
datasource获取方式的切换

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值