Change property value of a existing bean in spring at run time - spring

I have a web application deployed on Tomcat server. I have the following bean hiveDataSource created in my application-context.xml:
<!-- Hive Data Source for Connection Pooling -->
<bean id="hiveDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="url" value="jdbc:hive2://localhost:10000/demo48" />
<property name="driverClassName" value="org.apache.hive.jdbc.HiveDriver" />
<property name="username" value="hive" />
<property name="password" value="" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="5" />
<property name="maxActive" value="20" />
</bean>
I want to change the value of property URL, username and password at run time for bean hiveDataSource. Is there any way to change these property values at runtime?

The documentation says that these fields have protected access, so you wont be able to change their values.
Even if you do, by using reflection or in some other way, it's not likely that data source would just pick up these new values. It would probably have to be restarted or reinitialized in some way.

Related

Trouble with overriding properties in Spring-batch

We are using Spring 4.3.9 with Spring Batch 3. We are using maven to copy resources with filtering to merge profile-based properties into the configs at build time. I want to allow my DevOps engineers to override property file settings (db passwords) at deployment time to the environment specific property, so I've setup things as shown below, but the overrides don't work:
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="location" value="classpath:bluecost-OVERRIDE.properties" />
</bean>
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${datasource.database.driverClassName}" />
<property name="jdbcUrl" value="${datasource.database.url}" />
<property name="user" value="${datasource.database.username}" />
<property name="password" value="${datasource.database.password}" />
<property name="maxPoolSize" value="${datasource.maxPoolSize}" />
<property name="minPoolSize" value="${datasource.minPoolSize}" />
</bean>
The property file that maven merges with all default values looks like this:
datasource.database.driverClassName=com.ibm.db2.jcc.DB2Driver
datasource.database.url=jdbc:db2://localhost:50000/bluecost
datasource.database.username=not-real-id
datasource.database.password=not-real-pwd
datasource.maxPoolSize=50
datasource.minPoolSize=10
And finally, my bluecost-OVERRIDE.properties file has the correct values for just the username and password, configured like this:
# Overriding values for the datasource property values
datasource.database.username=db2inst
datasource.database.password=db2inst1
The override file is surely in the classpath (it wouldn't start without finding it anyway). It's throwing errors at runtime because of the invalid (default) userid/pwd.
Why doesn't it override the userid/pwd like I want it to?

Build Maven project without include Spring bean profile

I use Spring bean profile to separate each datasource environments:
<bean id="fooJDBCTemplate" class="com.rakuya.r_erp.task.dao.FooJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<beans profile="dev">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
</beans>
<beans profile="qa">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
<beans profile="prod">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://somewhere:3306/erp?characterEncoding=UTF-8"/>
<property name="username" value=""/>
<property name="password" value=""/>
</bean>
</beans>
And i use following command to build jar file and specify profile
mvn clean package -Dspring.profiles.active=prod
But i got the error about no definition of dataSource when executing the jar file.
It seems like Maven does not use the Spring profile to build jar.
How can I configure the Maven or Spring peofile to use the dataSource ?
Thx
You need to pass the profile -D switch when you run your app.
Since your bears are all the same type (DriverManagerDataSource) and the only thing that differs between environments are some of the properties, I think it would be best to get rid of the spring profiles and use properties to set these values. PropertyPlaceholderConfigurer should be able to handle this scenario where you set a vm param specifying what environment you want. Something like -Denv=dev.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:${env}.properties</value>
</list>
</property>
</bean>
Then you would only need one datasource bean like the following:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
And a property file for each environment named dev.properties, qa.properties, and prod.properties with values in each for db.driver, db.url, etc.
When spring starts up it will select the appropriate properties file based on the value passed in with -Denv and load the corresponding property values into your datasource bean.

Changing blob size on HSQLDB with spring datasource

I am configuring HSQLDB through Spring and C3P0, this creates the database for me if it doesn't exist.
<bean id="DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="org.hsqldb.jdbcDriver" />
<property name="jdbcUrl" value="jdbc:hsqldb:file:mydb/mydb" />
<property name="user" value="sa" />
<property name="password" value="" />
</bean>
However, I would like to initialize the BLOB size to 8kb instead of the 32kb default value, is it possible to set the parameter in Spring somehow? I know I can edit later the script file to set SET FILES LOB SCALE 32 to 8, but I would like it set on Spring/C3P0 if possible.
Yes. For new databases, several settings can be included on the URL or as properties.
To change the BLOB block size, add this line:
<property name="hsqldb.lob_file_scale" value="8" />
The properties are covered in the Guide:
http://www.hsqldb.org/doc/2.0/guide/dbproperties-chapt.html#dpc_db_file_mem

Spring service going down after DB connection down

I have a spring cxf web service application deployed into a JBOSS server. The service is working fine and once in a while(within 5-6 days after the server start) , I get and error"Could not open JDBC Connection for transaction; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object" and that particular service goes down
I have around 17 services inside this application and only the service which had this DB connection issue goes down till I restart the server.
Other services are up.
Below is my JDBC template configuration.
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="10" />
<property name="maxIdle" value="10" />
<property name="maxActive" value="100" />
<property name="maxWait" value="1000" />
<property name="validationQuery" value="select 1 from sysibm.sysdummy1" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="1200000" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="false" />
</bean>
Your help is greately appreciated.
I'd recommend that you switch to a JNDI data source managed by JBOSS.
It sounds like either a connection leak or that you have some really long-running processes that hold a database connection long-term, eventually exhausting your connection pool. It's also possible, though unlikely, that you have very high database latency, that a dead connection shows up in the pool, and that recognizing the dead connection, establishing a new one, and validating it takes longer than the 1 second you've given the pool.
You can try and change the datasource to the :
org.springframework.jdbc.datasource.DriverManagerDataSource
It's better to configure a data source with JBoss and do a Java EE-jndi lookup.
http://techdive.in/spring/spring-jndi-datasource-configuration-jboss

Setup Connection Pooling in Spring MVC

How can I setup connection pooling in Spring MVC? I am working on an intranet website powered by Spring MVC 2.5 and jQuery. This is my first attempt at web development.
I am not sure but, I am only using this in my spring configuration file and I saw this in the Spring MVC step By Step tutorial
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
This looks good during development and connection speed is fast but I am not sure if this will still holds true if many users are concurrently connected.
How can I achieve this? I have read that this is not an optimal connection datasource.
You might want to look at c3p0, which has some powerful configuration and optimization available.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="..." />
<property name="jdbcUrl" value="..." />
<property name="user" value="..." />
<property name="password" value="..." />
</bean>
Your current setup is correct, all you need to do in order to use basic connection pooling is use a DataSource implementation provided by a connection pooling library, in your case Apache DBCP. See this post for a few links to other alternatives, C3P0 being one of them.
Note that when you actually use the DataSource bean you're injecting wrap it in a SimpleJdbcTemplate or use DataSourceUtils to obtain a Connection - see Spring JDBC Documentation
For connection Pooling
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
//Add this two more parameters
<property name="**initialSize**" value="20" />
<property name="**maxActive**" value="30" />
</bean>
connection pool will create 20 database connection as initialSize is 20 and goes up to 30 Database connection if required as maxActive is 30.

Resources