如何在spring中等价配置得到原本由jndi配置实现的数据源?

来源:互联网 发布:ubuntu ant android 编辑:程序博客网 时间:2024/06/04 19:04

本文最后会附一个简单的maven控制台程序下载链接,你可以直接查看程序。

 

像本文标题说的,通常在spring web应用内配置数据源时,我们有种配置方式是在web容器中使用jndi的方式配置一个数据源。比如,tomcat内,经常会在%tomcat_home%/conf/catalina/localhost/文件夹内,放置一个web应用对应的xml配置文件,在其中<Context>内又包含了<Resource>,通常是下面的格式:

<?xml version="1.0" encoding="utf-8" ?><Context  path="/xxx"  docBase ="/home/xxx/proj/xxx"    reloadable="true"  >    <Resource        auth="Container"        name="jdbc/mysqltest"        factory="org.apache.commons.dbcp.BasicDataSourceFactory"        type="javax.sql.DataSource"        maxActive="50"        maxIdle="300"        username="root"        password="admin123"        maxWait="5000"        removeAbandoned="true"        driverClassName="com.mysql.jdbc.Driver"        url="jdbc:mysql://127.0.0.1:3306/phpmyadmin"    /></Context>

tomcat在解析上面的xml文件时,会在内部生成对应的jndi资源以供使用。

对应的,在spring工程内部的bean配置文件,比如application-resources.xml文件内,有如下的配置,以生成数据源对象bean:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">        <property name="jndiName" value="java:comp/env/jdbc/mysqltest"></property></bean>


现在的问题是:由于各种原因,当不想用这种方式进行配置时(即不想使用jndi方式),如何等价的在spring工程内部实现上面的配置?

这里先给出作者认为最等价的形式,如下:

    <bean id="propDs" class="org.springframework.beans.factory.config.PropertiesFactoryBean">        <property name="properties">            <props>                <prop key="type">javax.sql.DataSource</prop>                <prop key="maxActive">50</prop>                <prop key="maxIdle">300</prop>                <prop key="username">root</prop>                <prop key="password">admin123</prop>                <prop key="maxWait">5000</prop>                <prop key="driverClassName">com.mysql.jdbc.Driver</prop>                <prop key="url">jdbc:mysql://127.0.0.1:3306/phpmyadmin</prop>            </props>        </property>    </bean>    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSourceFactory"  factory-method="createDataSource">        <constructor-arg ref="propDs"></constructor-arg>    </bean>


 

如以上,如果你倾向于这种形式,那本文所要解决的问题也就结束了。

 

下面是其他相关的讨论。

1、为什么需要做这件事情?

首先是作者内心的纠结,觉得应该可以等价过去的;

其次是当你使用非web程序的时候,或者你对jndi不那么熟悉,或者系统内没有jndi provider,或者你就是想测试一下数据库的某些工作等等,你想快速的做个程序,连接上数据库,看看那边的情况,你还想保持spring的优雅,不愿意写那么多代码去各种初始化,我觉得此时你应该考虑一下上面的方案以及本文最后的程序内的形式。

2、为什么要强调等价配置?

实际上,达到不使用jndi,在spring内使用其他数据源配置还有别的形式,比如,下面的这种形式:

<bean id="dataSource02" class="org.apache.commons.dbcp.BasicDataSource">        <property name="maxActive" value="50"></property>        <property name="maxIdle" value="300"></property>        <property name="username" value="root"></property>        <property name="password" value="admin123"></property>        <property name="maxWait" value="5000"></property>        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>        <property name="url" value="jdbc:mysql://127.0.0.1:3306/phpmyadmin"></property></bean>

 

通常情况下,使用上面的这种形式也没有问题,但是,就像作者解决这个问题的另外一个原因一样,事情总有意外。作者面对的某个应用,其最初的开发者将BasicDataSourceFactory类进行了改写,在其中对用户名、密码等信息进行了转换处理(即对BasicDataSourceFactory类进行了方法扩展,这些方法在内部完成了属性字符串的转换工作等),然后将BasicDataSourceFactory所在的jar包重新进行了生成,也就是BasicDataSourceFactory类并不是一个普适正常的类了,它传递给BasicDataSource的属性值,已经与你在上面配置的值是不一样的了

虽然作者觉得这种做法没有什么用(作者最初采用了扩展BasicDataSource类的方案绕过了限制,但是觉得很不优雅),然而确实有同学认为可以通过这种方法隐藏数据库配置信息,比如密码等。

无论如何,当你遇到上面这种情况时,你要优雅,你就只能想着如何等价配置过来了。

3、其他方案?

<1> 与本文结论相似的变种。对properties bean进行.properties配置文件化,然后后面一样了,总之需要最终被加载到dataSource那个bean的创建里;

<2> 注解实现。spring的配置已经多到爆,没有注解型的实现方案怎么能算完整?作者这里仅给出相关的核心代码片段(下面是一个示意):

@Configurationpublic class MySqlConfig {@Bean(name=”dataSource”)public DataSource dataSource() throws Exception {    Properties props = new Properties();    // ……大段的装载配置到props内    DataSource objDs = BasicDataSourceFactory.createDataSource(props);    return objDs;}}


示例下载:http://download.csdn.net/download/smartcore/9977300