I am new to using application.properties and am struggling because Environment is always null. I have followed numerous examples such as the accepted answer shown on SO HERE; however, I keep getting the error message showing below. This is a Spring application and I know I don't actually need to go through this manual process per the article HERE. However, I have to show how to connect manually using the properties file. Where am I going wrong? Effectively, I want to hide my database credentials in application.properties and then read them into something like DriverManager.getConnection(env.getProperty("URL"), env.getProperty("USERNAME", env.getProperty("PASSWORD");
Attempting to use Environment:
#Component
#PropertySource("classpath:application.properties")
public class OpenConnection {
private volatile Connection con;
#Autowired
private Environment env;
public OpenConnection() {
}
#Bean
public Connection getInstance() {
try {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
con = dataSource.getConnection();
} catch (SQLException e) {
handleException(e);
}
return con;
}
application.properties
# MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/rentalportfolio?useTimezone=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
Error message
java.lang.NullPointerException: null
at com.crd.carrental.database.connectionoperations.OpenConnection.getInstance(OpenConnection.java:43) ~[classes/:na]
at com.crd.carrental.database.selectoperations.SelectExistingReservation.<init>(SelectExistingReservation.java:24) ~[classes/:na]
at com.crd.carrental.controllers.ExistingReservationController.lookupReservationId(ExistingReservationController.java:24) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_261]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_261]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_261]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_261]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171) ~[spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120) ~[spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:565) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:511) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:94) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:520) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:454) [spring-messaging-5.3.3.jar:5.3.3]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:144) [spring-messaging-5.3.3.jar:5.3.3]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_261]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_261]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_261]
I think that the problem is that you are using #Component on your OpenConnection rather than #Configuration
Here you can find some more examples, how to use properties in your Spring application
I recommend removing this OpenConnection class and let SpringBoot create your datasource for you on start up.
If you really want to create it yourself, check the docs. Here is an example:
#Configuration
public class DataSourceConfiguration {
#Bean
#ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
Related
I have started working on Spring Boot for a while. For a project, I am trying to use factory bean for datasource creation. Ultimately, i need to create datasources dynamically from another db table. I have a prototype bean that creates a new datasource each time i call context.getBean("getDbEndpointDatasource", args....)
#Bean
#Scope("prototype")
#Qualifier("getDbEndpointDatasource")
public DataSource getDbEndpointDatasource(String url, String className, String userName, String password) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(url);
dataSource.setDriverClassName(className);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
I am getting datasource by using below.
DataSource getDbEndpointDatasource = (DataSource) context.getBean("getDbEndpointDatasource",
"jdbc:postgresql://127.0.0.1/spring-test?user=spring-test&password=spring",
"org.postgresql.Driver", "spring", "spring");
So, with the configuration above, i get the below exception when i start spring boot.
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 103 more
I have been searching for a while why spring gives this exception. I also have another factory bean that is prototype scoped as well and it gives me a new object each time it is calld as expected. But here, i don't understand why i get this error. The number of arguments i passed to context.getBean method seems correct. Also, if i remove Scope annotation, i get no exception but it gives me the same datasource each time i call. I am not sure if i miss anything. It seems strange to me.
I appreciate if someone can give a clue or guide.
Thanks
Can you try like below.
DataSource endpointDatasource = (DataSource) context.getBean("getDbEndpointDatasource");
endpointDatasource.getDbEndpointDatasource("jdbc:postgresql://127.0.0.1/spring-test?user=spring-test&password=spring","org.postgresql.Driver", "spring", "spring");
I've two scheduled tasks that run at different time intervals. The first task is scheduled to run every 5 seconds and the second task is scheduled to run every 10 minutes.
#EnableScheduling
public class ScheduledTask {
#Autowired
private taskService taskService;
#Scheduled(every 5 second)
public void scheduleTaskA() {
taskService.taskA()
}
#Scheduled(every 10 minute)
public void scheduleTaskB() {
taskService.taskB()
}
}
public class TaskServiceImpl implements TaskService {
#PersistenceContext
private EntityManager entityManager;
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
}
Every time the second task is running it throws java.lang.IllegalStateException: Session/EntityManager is closed. Looks like the first task is closing the entityManager. How can I avoid this without changing #PersistenceContext annotation?
Full stack trace
java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:357) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:138) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.query.internal.AbstractProducedQuery.getMaxResults(AbstractProducedQuery.java:892) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getResultList(ProcedureCallImpl.java:716) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at org.hibernate.procedure.internal.ProcedureCallImpl.getSingleResult(ProcedureCallImpl.java:744) ~[hibernate-core-5.3.6.Final.jar:5.3.6.Final]
at sun.reflect.GeneratedMethodAccessor150.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:374) ~[spring-orm-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at com.sun.proxy.$Proxy149.getSingleResult(Unknown Source) ~[na:na]
at com.test.service.TaskServiceImpl.taskA(TaskServiceImpl.java:602) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:112) ~[classes/:0.0.1-SNAPSHOT]
at com.test.service.TaskServiceImpl....(TaskServiceImpl.java:163) ~[classes/:0.0.1-SNAPSHOT]
at com.test.schedule.ScheduledTask.scheduledTaskA(ScheduledTask.java:45) ~[classes/:0.0.1-SNAPSHOT]
at sun.reflect.GeneratedMethodAccessor143.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_171]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
I'm pretty sure you need to run the StoredProcedureQuery(s) in a transactional context. Please try adding #Transactional to each of your methods.
#Transactional
void taskA(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure1");
if(query.execute())
query.getSingleResult();
}
#Transactional
void taskB(){
StoredProcedureQuery query = entityManager.createStoredProcedureQuery("callStoreProcedure2");
if(query.execute())
query.getSingleResult();
}
You might also want to set the propagation to new to insure these each run within their own separate transaction #Tansacational(propagation = Propagation.REQUIRES_NEW) .
You are getting the error because you are trying to share same entity manager. Which is short living object.
You can apply following two solutions :
1) Inject EntityManagerFactory and inside of EntityManager, in method use factory to create EntityManager.
#PersistenceUnit(unitName= "em")
private EntityManagerFactory emf;
2) Create two different services let each service have there own entity manger instance.
(Not sure it will work second time when method will called by scheduler. Test it and let me know.)
I have a kafka listener, which receives the data correctly but EventData ss = consumerRecord.value() gives ClassCastException.
I am using default spring boot settings.
I am not sure how it receives the message correctly and when I try to use, it gives the exception.
#KafkaListener(topics = "${kafka.topic.event.model.message}")
public void receive(ConsumerRecord<String, EventData> consumerRecord) throws IOException, ClassNotFoundException {
LOGGER.info("received payload='{}'", consumerRecord.value());
EventData ss = consumerRecord.value();
}
It gives the exception:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to com.betstars.betsyncadapter.app.kafka.message.EventData
at com.betstars.betsyncadapter.app.kafka.message.KafkaMessageListenerForEventModel.receive(KafkaMessageListenerForEventModel.java:26) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:180) ~[spring-messaging-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:112) ~[spring-messaging-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48) ~[spring-kafka-1.1.6.RELEASE.jar:na]
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:174) ~[spring-kafka-1.1.6.RELEASE.jar:na]
... 10 common frames omitted
Spring Boot Apache Kafka auto-configuration uses StringDeserializer for the value by default:
https://github.com/spring-projects/spring-boot/blob/v2.0.0.RC1/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/kafka/KafkaProperties.java#L287
You should consider to use a org.springframework.kafka.support.serializer.JsonDeserializer for your EventData use-case:
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
spring.kafka.consumer.properties.spring.json.value.default.type=com.your.EventData
That's for the Spring Boot 2.0 though.
For the previous version you should use a JsonDeserializer extension:
public class EventDataJsonDeserializer extends JsonDeserializer<EventData> { }
for the property:
spring.kafka.consumer.value-deserializer = com.your.EventDataJsonDeserializer
Also double check if you configure "properties.specific.avro.reader: true" for your consumer
Caused by: java.lang.NullPointerException
at org.springframework.boot.actuate.endpoint.DataSourcePublicMetrics.initialize(DataSourcePublicMetrics.java:64) ~[spring-boot-actuator-1.3.2.RELEASE.jar:1.3.2.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_79]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
I disabled the metrics too but no luck
endpoints.enabled=false
endpoints.autoconfig.enabled=false
endpoints.metrics.enabled=false
The DataSourcePublicMetrics bean always gets created, even when the metrics are disabled. This causes a NullPointerException when the database connection is unavailable, causing spring boot not to start.
I am using Hikari datasource and it fails to construct data source object when database is unavailable. Hence NPE from DataSourcePublicMetrics bean. I am able to circumvent the issue creating a Hikari data source that is lazy initialized with database config even when database is unavailable for later use when database becomes available. Not sure why HikariDataSource does not have a constructor for lazy init. It does have a default constructor but database config can't be set using any setter method. This is useful for applications where database is not always necessary to start them up.
public class LazyConnectionDataSource extends HikariDataSource {
public LazyConnectionDataSource(HikariConfig config) {
config.validate();
config.copyState(this);
}
}
I have an application using playFramework, Spring & Hibernate like this:
Play-Spring-Data-JPA-APP
I want to implement multiple datasources with AbstractRoutingDataSource, so I have my custom class:
package mx;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
*
*/
public class MyRouting extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
System.out.println("Logic to determine the datasource");
return "key";
}
}
But when I try to set the datasource in my application.conf like this:
db.routingDS.dataSourceClassName = mx.MyRouting
I get a
[error] play - Error while stopping the application
play.api.PlayException: Cannot load plugin[An exception occurred during Plugin [com.edulify.play.hikaricp.HikariCPPlugin] initialization]
at play.api.WithDefaultPlugins$$anonfun$plugins$1$$anonfun$apply$9.apply(Application.scala:154) ~[play_2.10-2.3.10.jar:2.3.10]
at play.api.WithDefaultPlugins$$anonfun$plugins$1$$anonfun$apply$9.apply(Application.scala:130) ~[play_2.10-2.3.10.jar:2.3.10]
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:0.13.5]
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:0.13.5]
at scala.collection.immutable.List.foreach(List.scala:318) ~[scala-library.jar:0.13.5]
Caused by: play.api.Configuration$$anon$1: Configuration error[java.lang.ClassNotFoundException: mx.MyRouting]
at play.api.Configuration$.play$api$Configuration$$configError(Configuration.scala:94) ~[play_2.10-2.3.10.jar:2.3.10]
at play.api.Configuration.reportError(Configuration.scala:743) ~[play_2.10-2.3.10.jar:2.3.10]
at com.edulify.play.hikaricp.HikariCPDBApi$$anonfun$2.apply(HikariCPDBApi.scala:64) ~[play-hikaricp_2.10-2.0.6.jar:2.0.6]
at com.edulify.play.hikaricp.HikariCPDBApi$$anonfun$2.apply(HikariCPDBApi.scala:44) ~[play-hikaricp_2.10-2.0.6.jar:2.0.6]
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) ~[scala-library.jar:0.13.5]
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: mx.MyRouting
at com.zaxxer.hikari.util.UtilityElf.createInstance(UtilityElf.java:120) ~[HikariCP-2.3.8.jar:na]
at com.zaxxer.hikari.pool.PoolUtilities.initializeDataSource(PoolUtilities.java:102) ~[HikariCP-2.3.8.jar:na]
at com.zaxxer.hikari.pool.BaseHikariPool.<init>(BaseHikariPool.java:156) ~[HikariCP-2.3.8.jar:na]
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:60) ~[HikariCP-2.3.8.jar:na]
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:48) ~[HikariCP-2.3.8.jar:na]
Caused by: java.lang.ClassNotFoundException: mx.MyRouting
at java.net.URLClassLoader$1.run(URLClassLoader.java:372) ~[na:1.8.0_25]
at java.net.URLClassLoader$1.run(URLClassLoader.java:361) ~[na:1.8.0_25]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_25]
at java.net.URLClassLoader.findClass(URLClassLoader.java:360) ~[na:1.8.0_25]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_25]
(Im also using a db configuration with HikariCP)
I also tried to generate a jar with the class and the result is the same, Anyone has some idea about it? Thanks!
what you are trying to achieve is not possible thru play application config directly. The main problem is that by default play expects an URL and driver to create the Datasource (at least in play 2.3 and play 2.4).
In other words, play expects that always that you are going to create a datasource, you will be using a connection pool to a real database not to a RoutingDatasource.
Since you are using a JPA seed, you need to access the resources thru JNDI, so you need to add the datasource to the JNDI in some way.
This is how it can be achived:
In the application.conf only declare the datasources that will interact to the database. As many as you want:
# Database configuration
#
db.mydb1.driver=org.h2.Driver
db.mydb1.url="jdbc:h2:mem:play"
db.mydb1.jndiName=DB1DS
db.mydb2.driver=org.h2.Driver
db.mydb2.url="jdbc:h2:mem:play"
db.mydb2.jndiName=DB2DS
Now, in the persistence.xml ensure that you do not declare any datasource. (neither jta or not jta)
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Finally, in the Global.java or Global.scala, force into the JNDI the RoutingDatasource. The nasty part is that there's no documentation or post anyware of how Play manage the JNDI. Basically, Play creates an on memory JNDI using the class "InitialContext". This context is writable (thanks god) cause there are many application servers that protect their initial context.
//This is the routing Datasource in spring context
#Bean
public RoutingDatasource routingDataSource() {
RoutingDatasource rd = new RoutingDatasource();
java.util.HashMap ds = new java.util.HashMap();
ds.put("DB1DS","DB1DS");
ds.put("DB2DS","DB2DS");
rd.setTargetDataSources(ds);
return rd;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
java.util.Map props = new java.util.HashMap();
try{
//This is the magic line.
((javax.naming.Context)(new javax.naming.InitialContext())).bind("routingDataSource", ctx.getBean("routingDataSource"));
}catch(Exception e){}
props.put("javax.persistence.jtaDataSource", "routingDataSource");
return Persistence.createEntityManagerFactory(DEFAULT_PERSISTENCE_UNIT,props);
}
And finally just as you mentioned, create your own RoutingDatasource:
public class RoutingDatasource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return selectRandom("DB1DS","DBDS2");
}
}
Thats all. I hope it helps solving your problem.