How can I create a db2 connection in Spring boot without use application.properties? - spring

I need to build a connection to db2 database, but I can not use application.properties at this moment, so how can I create this connection?

You can implement a datasource bean in the app itself. For example:
#Configuration
public class MyClass {
#Bean
public DataSource getDataSource() {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName(JDBC_DRIVER_CLASS_NAME);
dataSourceBuilder.url(myprops.getJDBCUrl());
dataSourceBuilder.username(myprops.getJDBCUsername());
dataSourceBuilder.password(myprops.getJDBCPassword());
return dataSourceBuilder.build();
}
}
Then, make sure any autowired references to the data source are "lazy", so the app has time to load the properties (maybe from another file) and to instantiate the data source, as in:
#Lazy
#Autowired
private DataSource dataSource;

Related

SpringBoot web services multiple data sources only one working

I have developed two webservices using Spring Boot framework and I have them in the same project. Each webservice use a different DB, say ws1 uses Oracle1 and ws2 uses Oracle2. I have defined a DataBaseConfig with the beans definition but when I run the app, always works one webservice ( and it's always the same ).
DataBaseConfig
#Configuration
public class DataBaseConfig {
#Bean(name = "ora1")
#ConfigurationProperties(prefix="spring.datasource")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().build();}
#Bean(name = "ora2")
#ConfigurationProperties(prefix="spring.secondDatasource")
public DataSource sqliteDataSource() {
return DataSourceBuilder.create().build();}
#Bean(name = "clients")
#Autowired
#ConfigurationProperties(prefix = "spring.datasource")
#Qualifier("datasource")
public JdbcTemplate slaveJdbcTemplate(DataSource datasource) {
return new JdbcTemplate(datasource); }
#Bean(name = "places")
#Autowired
#Primary
#ConfigurationProperties(prefix = "spring.secondDatasource")
#Qualifier("secondDatasource")
public JdbcTemplate masterJdbcTemplate(DataSource secondDatasource) {
return new JdbcTemplate(secondDatasource);}
}
I have the services definition with the sql statements and the definition
#Service
public class ClientsService {
#Autowired
#Qualifier("clients")
private JdbcTemplate jdbcTemplate;
and the other service
#Service
public class PlacesService {
#Autowired
#Qualifier("places")
private JdbcTemplate jdbcTemplate;
Then in each controller I have de mapping #RequestMapping. When I run the app I have no connection-related errors and if I separate the webservices in 2 projects, each works fine.
You have a few things going wrong here, including some unnecessary annotations. See below, note the location of #Qualifier and the qualifier name:
#Bean(name = "clients")
public JdbcTemplate slaveJdbcTemplate(#Qualifier("ora1") DataSource datasource) {
return new JdbcTemplate(datasource);
}
#Bean(name = "places")
#Primary
public JdbcTemplate masterJdbcTemplate(#Qualifier("ora2") DataSource secondDatasource) {
return new JdbcTemplate(secondDatasource);
}
Instead of resolving by bean name, which is a bad idea IMO because it's not typesafe, why don't you use constructor injection and create the services in the configuration class (ditch #Service annotation). Create the DataSource and JdbcTemplate beans as usual, don't give them any names (the default is the method name), and also create new PlacesService(placesJdbcTemplate()). The result is a lot simpler code.
This is assuming you want both databases active at runtime. If not, use #Profile.

#Refreshscope with Datasource configuration

I am having a datasource configuration class in a Spring boot app. Snippet below
My configuration is fetched from Spring cloud config server. When I change my DB hostname and refresh using /refresh endpoint, the app is NOT using new DB host. ANy idea why ?
#Configuration
#RefreshScope
public classe DBConfig
{
#Resource
private Environment env;
private DataSource ehubDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("datasource.driverClassName"));
dataSource
.setUrl(env.getProperty("datasource.url"));
dataSource.setUsername(env.getProperty("datasource.username"));
dataSource.setPassword(env.getProperty("datasource.password"));
return dataSource;
}
}
As per docs,#RefreshScope will technically work on #Configuration, provided anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in #RefreshScope
So could you please check your "Environment.java", You may forget to specify #RefreshScope in Environment.java. Please share your Environment.java if it is not working.
Normally, the #Configuration class contains beans, which means the datasource method should be marked as #Bean. You need #RefreshScope on each bean.
For a datasource, you probably want #ConfigurationProperties, rather than writing code for each property. #ConfigurationProperties automatically includes #RefreshScope, so you actually don't need RefreshScope here.
With #ConfigurationProperties almost no code is needed.
#Configuration
public class DBConfig
{
#Bean
#ConfigurationProperties("datasource")
public DataSource ehubDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
return dataSource;
}
}
If your Environment does something other than read the properties files, then this may not work for you.
If you want the bean name to be different from the method name, you can provide a parameter to #Bean. The code below creates the same bean as above.
#Bean(name = "ehubDataSource")
#ConfigurationProperties("datasource")
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
return dataSource;
}

Spring Boot externalised configuration for DataSource not working

I have an application - using Spring 4.3.6 and Spring Boot 1.4.4 - which will be exported as a JAR. I want to connect to a remote Oracle database but I am having trouble externalising the configuration without breaking the application.
This is my current workaround:
import org.apache.tomcat.jdbc.pool.DataSource;
#Bean
public DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setUrl("jdbc:oracle:thin:#ip-address:port:orcl");
dataSource.setUsername("user");
dataSource.setPassword("password");
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
return dataSource;
}
With the above, my application is able to connect to the database and execute queries successfully. However, when I try to externalise the configuration as follows:
#Bean
#ConfigurationProperties(prefix="app.datasource")
public DataSource dataSource() {
return new DataSource();
}
// application.properties
app.datasource.url=jdbc:oracle:thin:#ip-address:port:orcl
app.datasource.username=user
app.datasource.password=password
app.datasource.driver-class-name=oracle.jdbc.OracleDriver
I will get the following error when trying to execute jdbcTemplate.update(query) in my Spring Boot Controller (note that without externalising the above works):
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: The url cannot be null
I have tried to remove #ConfigurationProperties and change app.datasource to spring.datasource. I have also tried to use DataSourceBuilder.create().build() which returns javax.sql.DataSource but the same error is thrown in both cases.
I'm doing something wrong. What's the correct way to successfully externalise the configuration?
Suppose you have two datasources for two different Oracle databases. Then you have the following properties file:
/path/to/config/application.properties
oracle1.username=YourUser1
oracle1.password=YourPassword1
oracle1.url=jdbc:oracle:thin:#localhost:1521:XE
oracle2.username=YourUser2
oracle2.password=YourPassword2
oracle2.url=jdbc:oracle:thin:#192.168.0.3:1521:XE
Then in a configuration file:
import oracle.jdbc.pool.OracleDataSource;
#Configuration
public class DatasourcesConfig {
#Autowired
private Environment env;
#Primary
#Bean(name = "dataSource1")
DataSource oracle1DataSource() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(env.getProperty("oracle1.username"));
dataSource.setPassword(env.getProperty("oracle1.password"));
dataSource.setURL(env.getProperty("oracle1.url"));
return dataSource;
}
#Bean(name = "dataSource2")
DataSource oracle2DataSource() throws SQLException {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setUser(env.getProperty("oracle2.username"));
dataSource.setPassword(env.getProperty("oracle2.password"));
dataSource.setURL(env.getProperty("oracle2.url"));
return dataSource;
}
}
If you want to specify the external location of your application.properties file when running the jar, then set the spring.config.location as a system property, you can try:
java -jar target/your-application-0.0.1.jar -Dspring.config.location=/path/to/config/
Make sure the application.properties file is excluded when building the jar
There should be no need to create the DataSourceyourself.
Make sure you have the
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
Dependecy in your classpath and the oracle driver and put following properties in your application.properties file:
spring.datasource.url=jdbc:oracle:thin:#ip-address:port:orcl
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
After that you should be able to #Autowired your DataSource
For more information have a look at:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-connect-to-production-database
You cannot override the predefined properties provided by spring boot.
Just use the following properties in application.properties file.
spring.datasource.url=jdbc:oracle:thin:#ip-address:port:orcl
spring.datasource.data-username=user
spring.datasource.data-password=password
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
See Also : https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
Apart from above, to clarify #ConfigurationProperties is used at class level and the prefix "app" not "app.datasource"
#ConfigurationProperties(prefix = "app")
Now you have a class named DbProperties and the properties of the class is same as the last part of the key in application.properties
public class DBProperties {
private String url;
private String username;
private String password;
// setters and getters
}
Now the actual config/component class should look like following.
#Component
#ConfigurationProperties(prefix = "app")
public class MyComponent {
DBProperties datasource = new DBProperties();
public DBProperties getDatasource() {
return datasource;
}
public void setDatasource(DBProperties datasource) {
this.datasource = datasource;
}
}
Please note
The instance variable name is datasource which is same as the second part of the key
datasource is a class level instance

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());
}
}

multiple datasources in Spring Boot application

I'm trying to using two database connections w/in a Spring Boot (v1.2.3) application as described in the docs (http://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/htmlsingle/#howto-two-datasources.
Problem seems to be that the secondary datasource is getting constructed with the properties for the primary datasource.
Can someone point out what I'm missing here?
#SpringBootApplication
class Application {
#Bean
#ConfigurationProperties(prefix="spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
public JdbcTemplate secondaryJdbcTemplate(DataSource secondaryDataSource) {
return new JdbcTemplate(secondaryDataSource)
}
#Bean
#Primary
#ConfigurationProperties(prefix="spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "primaryJdbcTemplate")
public JdbcTemplate jdbcTemplate(DataSource primaryDataSource) {
return new JdbcTemplate(primaryDataSource)
}
static void main(String[] args) {
SpringApplication.run Application, args
}
}
application.properties:
spring.datasource.primary.url=jdbc:oracle:thin:#example.com:1521:DB1
spring.datasource.primary.username=user1
spring.datasource.primary.password=
spring.datasource.primary.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.secondary.url=jdbc:oracle:thin:#example.com:1521:DB2
spring.datasource.secondary.username=user2
spring.datasource.secondary.password=
spring.datasource.secondary.driverClassName=oracle.jdbc.OracleDriver
Both JdbcTemplate beans will be getting created with the primary DataSource. You can use #Qualifier to have the secondary DataSource injected into the secondary JdbcTemplate. Alternatively, you could call the DataSource methods directly when creating the JdbcTemplate beans.

Resources