Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define DataSource bean on code

I would like to make a "First Access Database Setup Process" in my spring application and the only thing I can imagine as a solution would be to initialize the DataSource bean programatically.

My current bean is defined as:

<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>

but the ideal thing was to load it by myself in whenever I need it and with the parameter I define.

The scenario is that the user (administrator) comes to the application at the first time and I ask him the server, port and catalog to connect. I store it in a embeeded db and next time application start, a bean can check if the parameter are set on the embedded db and load it again.

Is it possible?

EDT: per @axtavt sugestion I'm goin with a proxy...

<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"/>

once with a Proxy implemented how do I cast it to the Original Bean?

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

will throw a java.lang.ClassCastException: $Proxy4 cannot be cast to org.apache.commons.dbcp.BasicDataSource

like image 488
Ruben Trancoso Avatar asked Mar 14 '10 19:03

Ruben Trancoso


2 Answers

You can create a factory to produce a DataSource like you want:

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

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

-

public class MyFactory {
    public DataSource createDataSource() {
        ... // produce a DataSource
    }
}
like image 162
axtavt Avatar answered Nov 09 '22 16:11

axtavt


You can externalize the database connection properties:

<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>

Now Spring will get them from a .properties file that is loaded on startup.

Another thing you'll want to think about if you're using a Java EE app server is JNDI connection pool. You'll have the JNDI name externalized, and the connection parameters are managed by the admin of the app server. I would say that's the preferred way to do it. Right now you still have a password in plain text - a bad idea.

like image 20
duffymo Avatar answered Nov 09 '22 14:11

duffymo