【问题标题】:Define DataSource bean on code在代码上定义 DataSource bean
【发布时间】:2011-01-27 11:00:54
【问题描述】:

我想在我的 spring 应用程序中创建一个“首次访问数据库设置过程”,我唯一能想到的解决方案就是以编程方式初始化 DataSource bean。

我当前的bean定义为:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/catalog" />
    <property name="username" value="condominium" />
    <property name="password" value="password" />
    <property name="validationQuery" value="SELECT 1" />
    <property name="testOnBorrow" value="true" />
    <property name="defaultAutoCommit" value="false" />
    <property name="maxWait" value="5000" />
</bean>

但理想的做法是在需要时自行加载它并使用我定义的参数。

场景是用户(管理员)第一次来到应用程序,我问他要连接的服务器、端口和目录。我将它存储在嵌入式数据库中,下次应用程序启动时,bean 可以检查是否在嵌入式数据库上设置了参数并再次加载。

有可能吗?

美国东部时间: 根据@axtavt 的建议,我将使用代理...

<bean id="dataSource" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="swappableDataSource"/>
</bean>
<bean name="swappableDataSource" class="org.springframework.aop.target.HotSwappableTargetSource">
    <constructor-arg ref="dummyDataSource"/>
</bean>
<bean id="dummyDataSource" factory-bean="dataSourceFactory" factory-method="createDataSource" destroy-method="close"/>
<bean id="dataSourceFactory" class="com.condominium.spring.factory.DataSourceFactory"/>

一旦实现了代理,我如何将其转换为原始 Bean?

Object o = ctx.getBean("dataSource");
BasicDataSource ds = (BasicDataSource)o;

会抛出 java.lang.ClassCastException: $Proxy4 cannot be cast to org.apache.commons.dbcp.BasicDataSource

【问题讨论】:

标签: spring datasource


【解决方案1】:

你可以创建一个工厂来生产你想要的DataSource:

<bean id = "dataSourceFactory" class = "MyFactory" />

<bean id = "dataSource" factory-bean = "dataSourceFactory" factory-method = "createDataSource" />

-

public class MyFactory {
    public DataSource createDataSource() {
        ... // produce a DataSource
    }
}

【讨论】:

  • 这样我也应该从工厂创建 EntityManger 对吗?因为现在,它是在 .xml 中定义的,并且依赖于数据源
  • 既然工厂是在上下文中定义的,我们不会陷入同样的​​问题吗?
  • @Ruben:不,你不应该。这个 sn-p 创建一个名为 dataSource 的 bean。这个 bean 可以像任何其他 bean 一样使用。唯一不同的是Spring会调用你自己的工厂代码来实例化它。
  • 感谢@axtavt,但该应用程序将在启动时创建它。下次我需要在运行时更改它的参数时,您如何将 is 传递给仍然具有第一个参数的实体管理器?
  • @Ruben:如果你想在运行时改变它,那么你需要创建一个代理。
【解决方案2】:

您可以外部化数据库连接属性:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
    <property name="validationQuery" value="SELECT 1" />
    <property name="testOnBorrow" value="true" />
    <property name="defaultAutoCommit" value="false" />
    <property name="maxWait" value="5000" />
</bean>

现在 Spring 将从启动时加载的 .properties 文件中获取它们。

如果您使用的是 Java EE 应用服务器,您需要考虑的另一件事是 JNDI 连接池。您将外部化 JNDI 名称,并且连接参数由应用服务器的管理员管理。我会说这是首选的方法。现在你仍然有一个纯文本密码 - 一个坏主意。

【讨论】:

  • 这很重要,但在我的情况下,我需要(用户需要)在运行时定义它。我永远不会知道用户想要连接到哪里。我正在使用 tomcat。
  • @duffymo 你能解释一下属性文件的名称是在哪里配置的
  • Tomcat 支持 JNDI 命名数据源。你必须知道一些事情。无论如何,您都必须反弹服务器以获取更改,因为 Spring 在启动时读取应用程序上下文。
  • 这是 Spring PropertyPlaceholderConfigurer:static.springsource.org/spring/docs/2.5.x/api/org/…。在这种情况下,你把它放在 WEB-INF/classes 中。
【解决方案3】:

我使用的代理方法与您提到的完全相同。要摆脱java.lang.ClassCastException,您可以从HotSwappableTargetSource bean 获取数据源,如下所示。

HotSwappableTargetSource swapper = ctx.getBean(HotSwappableTargetSource.class);
BasicDataSource ds = (BasicDataSource) swapper.getTarget();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 2019-09-28
    相关资源
    最近更新 更多