Spring boot how to use Hikari auto configuration but set username/password at runtime - spring-boot

I am using Spring boot 2.0.1 with Hikari CP and want to use application properties to set Hikari datasource properties like Connection timeout, Maximum pool size etc but the username and password should be set at runtime. I tried below but when the datasource is created, it doesn't have the Connection timeout value I am trying to set.
Below is the code for datasource bean.
#Value("${spring.datasource.url}")
private String url;
#ConfigurationProperties(prefix = "spring.datasource.hikari")
#Bean
public DataSource dataSource() throws Exception {
//User name and password is fetched from some other data storage
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(url);
hikariConfig.setUsername(username);
hikariConfig.setPassword(password);
//The data source created here doesn't have connection timeout value
//set by me
return new HikariDataSource(hikariConfig);
}
Below is my application properties file
spring.datasource.url={Our DB URL}
spring.datasource.hikari.maximumPoolSize=100
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.poolName=SpringBootJPAHikariCP
spring.datasource.hikari.connectionTimeout=40000
spring.datasource.hikari.driver-class-
name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
I referred to below Spring documentation but it just talks about auto configuring properties like url and credentials (which worked) but not about connection timeout and idle timeout etc.
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-configure-a-datasource
Please let me know if I am missing anything.

#ConfigurationProperties(prefix = "spring.datasource.hikari")
#Bean
#Primary
public DataSource dataSource(String username,String password) {
return DataSourceBuilder.create().username(username).password(password).build();
}
and use these in yml/property file without giving username and password property.
spring:
profiles: dev
# Development database configuration
datasource.hikari:
driverClassName: oracle.jdbc.driver.OracleDriver
jdbcUrl: jdbc:oracle:thin:#url:1621:sid
type: com.zaxxer.hikari.HikariDataSource
connectionTimeout:40000
This will work. Let me know if it doesn't work for you.

Related

Spring-boot 2 ignoring Hikari specific properties

I'm trying to configure some Hikari specific properties for the datasource, and can't figure out how to do that left alone, that I don't even see how it suppose to work.
According to the Spring-boot doc you should be able to configure lots of additional props, for example, spring.datasource.hikari.transaction-isolation. So I have application.properties file with a content
spring.application.name=My App
# DB
spring.datasource.url=jdbc:sqlserver://localhost;databaseName=dbname
spring.datasource.username=user
spring.datasource.password=passw
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=30
spring.datasource.hikari.transaction-isolation=TRANSACTION_READ_COMMITTED
From what I understand from the docs, this should be enough for Spring-boot 2 to initialize Hickory datasource with the additional properties. However, when I run my application I can see that the datasource created with only generic spring.datasource.* properties.
I debugged application initialisation and looked at org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration class. I can see Spring uses Hikari datasource and creates an instance of HikariDataSource.class, but created datasource doesn't have any specific properties set. What I don't understand, is how it even possible to have some additional properties if the properties parameter has the actual type of DataSourceProperties which has no knowledge of any hikari specific properties. I thought it would be something hikari specific but it is not.
/**
* Hikari DataSource configuration.
*/
#Configuration(proxyBeanMethods = false)
#ConditionalOnClass(HikariDataSource.class)
#ConditionalOnMissingBean(DataSource.class)
#ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
#Bean
#ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
I can imagine that there maybe another call to configure the datasource later, but I can't find it and when inspecting datasource, at runtime, I can see they not set. I must be missing something here, so any help would be appreciated.
P.S. I also tried to use manual configuration but hit an another issue with Flyway.

Spring Boot - How to check number of active connections in the connection pool

I am using Spring Boot 1.5.17 with multiple data sources configured. One of my data sources is configured as follows.
#Primary
#Bean
#ConfigurationProperties("app.primary.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
Now how do I get or log the number of active connections in the connection pool for this data source?
It's a bit late , but DataSource interface doesn't have any methods that lets you do this, but if you are using HikariCP (which is the default).
You could do this.
(HikariDataSource)dataSource).getHikariPoolMXBean().getActiveConnections()
Solution (Kotlin code):
#Autowired var dataSource: DataSource
val hikaridataSource = dataSource as HikariDataSource
logger.info(
active: ${hikaridataSource.hikariPoolMXBean.activeConnections} " + "idle: ${hikaridataSource.hikariPoolMXBean.idleConnections} " + "threadsAwaitingConnection: ${hikaridataSource.hikariPoolMXBean.threadsAwaitingConnection}"
)

Unable to update hikari datasource configuration in spring boot app

Hikari datasource configurations always taking as default values. even though i provide the actual configurations in application.yml file.
MainApp.java
#SpringBootApplication
public class MainApp {
public static void main(String[] args) {
SpringApplication.run(MainApp.class, args);
}
#Bean
#Primary
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
//I use below method to set password from different approach instead of taking from app.yml
#Bean
public DataSource dataSource(DataSourceProperties properties) {
DataSource ds = properties.initializeDataSourceBuilder()
.password("setting a password from vault")
.build();
return ds;
}
}
application.yml
spring:
application:
name: demo
datasource:
hikari:
connection-timeout: 20000
minimum-idle: 5
maximum-pool-size: 12
idle-timeout: 300000
max-lifetime: 1200000
auto-commit: true
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://ip:port;databaseName=sample
username: username
Using Spring 2.1.1.RELEASE and when i start the application i logged the Hikari logs and it says all default values. So i did debugged on the second bean datasource and its actually HikariDatasource and except default values rest of them are empty and not reflecting the given values from the application.yml. Please recommend or comment if i misconfigured anything or done any mistake!

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

What are the good ways to configure database connection?

I placed the database configuration inside a configuration class :
#Configuration
#ComponentScan("com.ambre.pta")
#EnableTransactionManagement
#PropertySources({
#PropertySource("classpath:fr/referentiel.properties")
})
public class ApplicationContextConfig {
#Autowired
private Environment env;
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean(name = "viewResolver")
public InternalResourceViewResolver getViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean(name = "dataSource")
public DataSource getDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#192.168.1.123:1521:xe");
dataSource.setUsername("pta");
dataSource.setPassword("pta");
return dataSource;
}
...
}
The problem is that everytime the project will be delivered to a different customer then the developer has to modify these configs and rebuild the project and finally regenrate the war file.
So are there simple procedures to change database configs without rebuilding nor regenerating the war file ?
You can move DB configuration into external properties.
Add something like this
#PropertySources({
#PropertySource("classpath:fr/referentiel.properties")
#PropertySource("${db.properties}")
})
and then when you run your application just add this parameter (notice 'file:' prefix)
-Ddb.properties=file:/path-to.properties
you can access db properties in your config like this
#Autowired
private Environment env;
...
dataSource.setDriverClassName(env.getProperty("db.driver"));
dataSource.setUrl(env.getProperty("db.url"));
dataSource.setUsername(env.getProperty("db.username"));
dataSource.setPassword(env.getProperty("db.password"));
or with #Value annotation, e.g.
#Value("${db.driver}")
private String dbDriver;
Properties file path-to.properties should be just a regular properties file. So
db.driver=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:#192.168.1.123:1521:xe
db.username=pta
db.password=pta
I suggest you to use Spring boot which provides out of the box template projects. Also, setting up db connection in a Spring boot app is very simple. These are the two ways I have used so far.
If you want an in memory database, you can just include H2/HSQLDB/DERBY dependency in you pom.xml file and you are good to go. Spring boot sees these dependencies in you pom and creates a data source out of the box for you. One downside with these databases is they don't provide persistent storage.
If you want a persistent storage, like PostgreSQL, you can include the dependency in your pom.xml file and maintain a application.properties file inside your /src/main/resources folder.
For example, if you have a postgresql database track-courier running on your local machine on port 5432, the contents of this file will look something like below
spring.datasource.url=jdbc:postgresql://localhost:5432/track-courier
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
And you don't need to manually create any data source bean in a configuration class. Spring boot take care of that out of the box. You can look at this link for reference.
You can use datasource for connecting to DB.
Below is sample code to connect database using data souce.
#Bean
public DataSource dataSource_aw_es() {
DataSource dataSource = null;
Context ctx = null;
try {
ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:/comp/env/jdbc/DataSourcename");
} catch (NamingException e) {
}
return dataSource;
}
You just need to configure data source in your server.
Most important is , no need to share the db credentials to connect to DB.
Below is configuration for data source on server.(Below configuartion is for Tomcat server.We need to configure below snippet in context.xml of tomcat server.)
<Resource name="jdbc/DataSourceName" auth="Container" type="javax.sql.DataSource"
maxActive="-1" maxIdle="-1" maxWait="-1"
username="user" password="password"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://IP_DB:7011/Schema_name"/>

Resources