自己定制spring的数据源

本文详细介绍了如何优化数据源配置,通过引入工厂类来简化部署时的数据源获取方式。从传统的XML配置转向使用JNDI查找或直接使用JDBC驱动创建数据源,实现灵活的配置切换。通过引入自定义工厂类,只需通过修改属性文件中的一个开关参数即可轻松切换数据源获取策略,提高了部署效率。

说明:本文摘自优快云的一位网友的博客。

最近在做项目,开发时是通过driver创建datasource的,配置如下

 

  1. <beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
  2.  
  3.     <propertyname="driverClassName"value="${dataSource.driverClassName}"/> 
  4.  
  5.     <propertyname="url"value="${dataSource.url}"/> 
  6.  
  7.     <propertyname="username"value="${dataSource.username}"/> 
  8.  
  9.     <propertyname="password"value="${dataSource.password}"/> 
  10.  
  11. </bean> 
实施时是通过jndi查找得到datasource,配置如下:
  1. <beanid="dataSource"class="org.springframework.jndi.JndiObjectFactoryBean"> 
  2.  
  3.     <propertyname="jndiName"value="${dataSource.jndiName}"/> 
  4.  
  5. </bean> 
其中属性文件是通过propertyConfigurer导入的:
  1. <beanid="propertyConfigurer"  
  2.  
  3.     class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" 
  4.  
  5.     dependency-check="none"> 
  6.  
  7.     <propertyname="fileEncoding"value="UTF-8"/> 
  8.  
  9.     <propertyname="locations"> 
  10.  
  11.         <list> 
  12.  
  13.             <value>classpath:spring-app.properties</value> 
  14.  
  15.         </list> 
  16.  
  17.     </property> 
  18.  
  19. </bean> 
属性 文件的内容如下:
  1. dataSource.jndiName=jdbc/myDataSource 
  2.  
  3. dataSource.driverClassName=oracle.jdbc.driver.OracleDriver 
  4.  
  5. dataSource.url=jdbc:oracle:thin:@localhost:1521:myServId 
  6.  
  7. dataSource.username=myUser 
  8.  
  9. dataSource.password=myPassword 
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 的代码,自己写了一个数据源的工厂类:
  1. package laochake.spring.datasource; 
  2.  
  3. import javax.naming.NamingException; 
  4.  
  5. import javax.sql.DataSource; 
  6.  
  7. import org.springframework.beans.factory.FactoryBean; 
  8.  
  9. import org.springframework.beans.factory.InitializingBean; 
  10.  
  11. import org.springframework.jdbc.datasource.DriverManagerDataSource; 
  12.  
  13. import org.springframework.jndi.JndiLocatorSupport; 
  14.  
  15. import org.springframework.util.StringUtils; 
  16.  
  17. /**
  18. * 数据源工厂bean,通过 jndi 属性判断是从jndi取得数据源还是用jdbc驱动创建数据源<br>
  19. * 设计此类的目的是简化部署时的配置,即只同过设置定jndi的值就可以自动切换数据源的获取方式
  20. * @author laochake
  21. * @since 2007-12-13 下午01:26:46
  22. */ 
  23.  
  24. public class DataSourceFactoryBeanimplements FactoryBean,InitializingBean { 
  25.  
  26.    
  27.  
  28. /**缓存数据源对象*/ 
  29.  
  30. private DataSource dataSource; 
  31.  
  32. /**是否jndi数据源*/ 
  33.  
  34. private boolean jndi; 
  35.  
  36. /**数据源的名字(如果是jndi数据源)*/ 
  37.  
  38. private String jndiName; 
  39.  
  40. /**jdbc驱动类(非jndi的情况)*/ 
  41.  
  42. private String driverClassName; 
  43.  
  44. /**数据库的url(非jndi的情况)*/ 
  45.  
  46. private String url; 
  47.  
  48. /**用户名(非jndi的情况)*/ 
  49.  
  50. private String username; 
  51.  
  52. /**密码(非jndi的情况)*/ 
  53.  
  54. private String password; 
  55.  
  56.  
  57.  
  58. //TODO:此处省略了属性的set方法 
  59.  
  60.  
  61.  
  62. /**
  63. * 初始化
  64. * @author laochake
  65. * @since 2007-12-13 下午01:48:03
  66. * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
  67. */ 
  68.  
  69. public void afterPropertiesSet()throws Exception { 
  70.  
  71.    if(this.isJndi()){ 
  72.  
  73.     if (!StringUtils.hasText(this.jndiName)) { 
  74.  
  75.      throw new IllegalArgumentException("jndiName is required"); 
  76.  
  77.     } 
  78.  
  79.    }else
  80.  
  81.     if (!StringUtils.hasText(this.driverClassName)) { 
  82.  
  83.      throw new IllegalArgumentException("driverClassName is required"); 
  84.  
  85.     } 
  86.  
  87.     if (!StringUtils.hasText(this.url)) { 
  88.  
  89.      throw new IllegalArgumentException("url is required"); 
  90.  
  91.     } 
  92.  
  93.     if (!StringUtils.hasText(this.username)) { 
  94.  
  95.      throw new IllegalArgumentException("username is required"); 
  96.  
  97.     } 
  98.  
  99.     if (!StringUtils.hasText(this.password)) { 
  100.  
  101.      throw new IllegalArgumentException("password is required"); 
  102.  
  103.     } 
  104.  
  105.    } 
  106.  
  107.    //在初始化时就创建数据源 
  108.  
  109.    this.createDataSource(); 
  110.  
  111.  
  112. /**
  113. * 实现 FactoryBean 的方法,取得对象
  114. * @author laochake
  115. * @since 2007-12-13 下午01:33:35
  116. * @see org.springframework.beans.factory.FactoryBean#getObject()
  117. */ 
  118.  
  119. public Object getObject() { 
  120.  
  121.    DataSource ds = this.createDataSource(); 
  122.  
  123.    return ds; 
  124.  
  125.  
  126.  
  127.  
  128. /**
  129. * 创建数据源对象,并保存到 this.dataSource属性
  130. * @author laochake
  131. * @since 2007-12-13 下午01:46:44
  132. * @return
  133. */ 
  134.  
  135. protected DataSource createDataSource(){ 
  136.  
  137.    DataSource ds = this.dataSource; 
  138.  
  139.    if(ds==null){ 
  140.  
  141.     try
  142.  
  143.      if(this.isJndi()){ 
  144.  
  145.       ds = new JndiDataSourceSupport().lookupDataSource(this.jndiName); 
  146.  
  147.      }else
  148.  
  149.       ds=new DriverManagerDataSource(driverClassName, url, username, password); 
  150.  
  151.      } 
  152.  
  153.     }catch(Throwable err){ 
  154.  
  155.      throw new RuntimeException(err); 
  156.  
  157.     } 
  158.  
  159.    } 
  160.  
  161.    this.dataSource=ds; 
  162.  
  163.    return ds; 
  164.  
  165.  
  166. /**
  167. * 实现 FactoryBean 的方法,取得工厂创建的对象类型
  168. * @author laochake
  169. * @since 2007-12-13 下午01:42:57
  170. * @see org.springframework.beans.factory.FactoryBean#getObjectType()
  171. */ 
  172.  
  173. public Class getObjectType() { 
  174.  
  175.    return javax.sql.DataSource.class
  176.  
  177.  
  178.  
  179.  
  180. /**
  181. * 实现 FactoryBean 的方法,是否单例模式(始终返回true)
  182. * @author laochake
  183. * @since 2007-12-13 下午01:43:29
  184. * @see org.springframework.beans.factory.FactoryBean#isSingleton()
  185. */ 
  186.  
  187. public boolean isSingleton() { 
  188.  
  189.    return true
  190.  
  191.  
  192. /**
  193. * jndi数据源查找类(内部私有类)
  194. * @author laochake
  195. * @since 2007-12-13 下午01:49:09
  196. */ 
  197.  
  198. private class JndiDataSourceSupportextends JndiLocatorSupport{ 
  199.  
  200.    public DataSource lookupDataSource(String jndiName)throws NamingException{ 
  201.  
  202.     return (DataSource)super.lookup(jndiName, javax.sql.DataSource.class); 
  203.  
  204.    } 
  205.  
  206.  
  207.  
  208.  
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定义方式如下:

 

  1. <beanid="dataSource"class="com.gdcn.spring.datasource.DataSourceFactoryBean"> 
  2.  
  3.     <description><![CDATA[ 数据源定义 ]]></description> 
  4.  
  5.     <propertyname="jndi"value="${dataSource.IS_JNDI}"/> 
  6.  
  7.     <propertyname="jndiName"value="${dataSource.jndiName}"/> 
  8.  
  9.     <propertyname="driverClassName"value="${dataSource.driverClassName}"/> 
  10.  
  11.     <propertyname="url"value="${dataSource.url}"/> 
  12.  
  13.     <propertyname="username"value="${dataSource.username}"/> 
  14.  
  15.     <propertyname="password"value="${dataSource.password}"/> 
  16.  
  17. </bean> 
修改后的属性 文件的内容如下:
  1. dataSource.IS_JNDI=true 
  2.  
  3. dataSource.jndiName=jdbc/myDataSource 
  4.  
  5. dataSource.driverClassName=oracle.jdbc.driver.OracleDriver 
  6.  
  7. dataSource.url=jdbc:oracle:thin:@localhost:1521:myServId 
  8.  
  9. dataSource.username=myUser 
  10.  
  11. dataSource.password=myPassword 
  12.    
dataSource.IS_JNDI=true

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获取方式的切换。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值