Spring Boot (Batch) - Inject Datasource - spring-boot

I have a Spring Boot (batch-oriented) application that uses a datasource in order to finalize a batch job and write stuff to the database.
I have the datasource(s) defined inside the application.yml like:
spring:
datasource:
url: jdbc:h2:mem:JavaSpringBootBatch
username: sa
password:
profiles: # default, development, production
active: default, development
---
spring:
h2:
# ...config/settings here
profiles: development
---
spring:
datasource:
# ...datasource config here
profiles: production
The issue is when I try to inject the datasource into one of the Spring config files:
#Configuration
public class PlayerBatchConfig {
...
#Bean
public ItemWriter<Player> writer(final DataSource dataSource) {
final JdbcBatchItemWriter<Player> jdbcItemWriter = new JdbcBatchItemWriter<>();
...
jdbcItemWriter.setDataSource(dataSource);
jdbcItemWriter.setSql(sql.toString());
return jdbcItemWriter;
}
}
...it tells me that:
Could not autowire. There is more than one bean of 'DataSource' type.
Beans:
dataSource (DataSourceConfiguration.class)
dataSource (EmbeddedDataSourceConfiguration.class)
I also tried to inject the datasource like:
#Configuration
public class PlayerBatchConfig {
#Bean
#ConfigurationProperties(prefix = "datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
...
}
...but no luck :( , although the issue with the two datasources goes away eventually.
Any clues how to "circumvent" that?

Since you have 2 datasources you need the annotate them with the #Qualifier the datasources bean and when you use them as well. Spring is telling you it doesn't know which one you want to use.

The DataSource which you want to use annotate it with #Primary, refer spring-boot documentation here for further info. Along with #Primary you might also need to use #Qualifier for controlling the bean injection.

Related

Spring ShedLock without Database

I want to disable ShedLock with a configuration yml property. So i don't have to create the table shedlock, if it is not necessary. Is there a way to disable Shedlock usage?
I tried to remove #Bean lockProvider but then I got this message:
No qualifying bean of type 'net.javacrumbs.shedlock.core.LockProvider
If you are using ShedLock in combination with the shedlock-spring dependency, there probably is a #EnableSchedulerLock somewhere in your application. Move the LockProvider bean setup together with the annotation to a separate #Configuration class and add a #ConditionalOnProperty annotation, for example:
#Configuration
#EnableSchedulerLock
#ConditionalOnProperty(value = "shedlock.enabled", matchIfMissing = true)
public class ShedLockConfig {
#Bean
public LockProvider lockProvider(DataSource dataSource) {
// ...
}
}
And add the property
shedlock:
enabled: true
To your application.yml

Warning: Not loading a JDBC driver as driverClassName property is null, in springboot working with two datasources

I have currently configured spring boot to work with two different datasources. The application is working fine, however when I start the spring boot application I get an warning repeated 10 times like below:
2018-06-05 10:28:15.897 WARN 8496 --- [r://myScheduler] o.a.tomcat.jdbc.pool.PooledConnection : Not loading a JDBC driver as driverClassName property is null.
As I mentioned this is not affecting my application, but I would like to know why I am having this kind of warning and if there is any way to fix it.
When using two or more datasources you need to configure them yourself. In that case Spring Boot's DataSourceAutoConfiguration (and also DataSourceProperties) won't be used.
You most probably have the related DB details like the name of the JDBC driver class name in application.properties file as follows:
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
primary.datasource.url=jdbc:sqlserver://xxx.yyy.zzz.www:1433;databaseName=primaryDB
primary.datasource.username=username
primary.datasource.password=password
other.datasource.url=jdbc:sqlserver://xxx.yyy.zzz.www:1433;databaseName=otherDb
other.datasource.username=otheruser
other.datasource.password=otherpassword
Thus, to set the driver class name for the datasource just say:
#Value("${spring.datasource.driver-class-name}")
String driverClassName;
#Primary
#Bean(name = "primaryDb")
#ConfigurationProperties(prefix = "primary.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().driverClassName(driverClassName).build();
}
#Bean(name = "otherDb")
#ConfigurationProperties(prefix = "other.datasource")
public DataSource otherDataSource() {
return DataSourceBuilder.create().driverClassName(driverClassName).build();
}

Disable production datasource autoconfiguration in a Spring DataJpaTest

In my application.yml, I have the following configuration (to be able to customize variable on different environment with docker/docker-compose) :
spring:
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
The trouble is that Spring tries to autoconfigure this datasource while I am in #DataJpaTest, so with an embedded H2 database, and obviously it does not like placeholders....
I tried to exclude some autoconfiguration :
#DataJpaTest(excludeAutoConfiguration =
{DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
But then, nothing works, entityManagerFactory is missing, ...
I could probably use profiles but if possible I preferred another solution.
Did you try defining your own Datasource bean?
#Import(JpaTestConfiguration.class)
#DataJpaTest
#Configuration
public class JpaTestConfiguration{
//...
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
//...
}

How do you autowire/inject your datasource in Spring-boot?

I have been working with Spring boot for a bit now, and the datasource is always configured in your application.properties in every example I have seen, kind of like this:
# DataSource configuration
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/abcdef
spring.datasource.username=******
spring.datasource.password=******
However, lately I have been trying to integrate Spring Social, and the examples I have seen configure it in java in a config file like this:
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
dataSource.setUsername(env.getProperty("db.username"));
dataSource.setPassword(env.getProperty("db.password"));
return dataSource;
}
This allows for the datasource object to later be injected or autowired into the social config as seen here for example.
My question is, do I need to configure a datasource bean like this to be able to later inject the datasource, or will Spring-boot handle that for me?
Not a Spring (or Boot) expert by any means, but Spring Boot will auto-provide a Bean of type DataSource if the properties are there and there's a requirement for it. To use it you just #Autowire it.
Try this . If there are multiple #Configuration in springboot , You can import the the other config(DataSourceConfig) into your main AppConfig.
And then Using #PropertySource pull in the db url,username,password etc
https://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html
#Configuration
#Import(DataSourceConfig.class)
#PropertySource("classpath:application.properties")
public class SpringbatchConfig {
#Autowired
DataSourceConfig dataSourceConfig;
#Bean
public void myService myService() {
return new myServiceImpl(dataSourceConfig.dataSource());
}
}

Spring Boot Application with dependency having multiple datasources

I am trying to create a Spring Boot Application, with a dependency jar which has got context.xml configured with multiple datasources.
In My spring boot application, I added #ImportResource("context.xml") to the #Configuration class and now, I get an exception that
"No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 4: XXXDataSource,YYYDataSource,ZZZDataSource,aaaaDataSource".
I read the documentation on multiple datasources in Spring Boot, but unable to fix this issue. Not sure, how I can configure my class, as I cannot change the dependency jar to change the way datasources are configured.
Please help!
You can use the "Primary" attribute on your datasource bean to make your autowiring choose it by default.
<bean primary="true|false"/>
If you are using Java configuration, use the #Primary annotation instead.
http://docs.spring.io/spring-framework/docs/4.0.4.RELEASE/javadoc-api/org/springframework/context/annotation/Primary.html
#Component
public class FooService {
private FooRepository fooRepository;
#Autowired
public FooService(FooRepository fooRepository) {
this.fooRepository = fooRepository;
}
}
#Component
public class JdbcFooRepository {
public JdbcFooService(DataSource dataSource) {
// ...
}
}
#Primary
#Component
public class HibernateFooRepository {
public HibernateFooService(SessionFactory sessionFactory) {
// ...
}
}
If this still doesn't resolve the issue, you can name the bean, and use the #Qualifier annotation in your java classes, or use the "ref" attribute in your Spring XML configuration.
https://spring.io/blog/2014/11/04/a-quality-qualifier
#Autowired
#Qualifier( "ios") // the use is unique to Spring. It's darned convenient, too!
private MarketPlace marketPlace ;
If you require one of the datasources in the jar and are unable to modify the configuration, rather than importing the xml from the jar, copy the configurations you need into your own local spring context configuration.

Resources