springboot spring datasource tomcat properties not working - spring-boot

I am working on a springboot application with spring jpa with spring starter version <version>2.2.4.RELEASE</version>
I have defined below properties for tomcat and also excluded HikariCP NOTE: HikariCP is also not working
application.properties
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.tomcat.initial-size=30
spring.datasource.tomcat.max-wait=60000
spring.datasource.tomcat.max-active=300
spring.datasource.tomcat.min-idle=30
spring.datasource.tomcat.default-auto-commit=true
I've tried all combinations and also used default but I am getting below error after 2-3 API calls .
o.h.engine.jdbc.spi.SqlExceptionHelper : [http-nio-8080-exec-5] Timeout: Pool empty. Unable to fetch a connection in 30 seconds, none available[size:4; busy:
4; idle:0; lastwait:30000].

The problem is with the deployment. I am deploying the app to cloudfoundry, and it by default adds profile called cloud. So, I created a bean of DataSource for "cloud" profile like below:
#Configuration
#Profile("cloud")
public class CloudConfig extends AbstractCloudConfig {
#Bean
public DataSource dataSource() {
PooledServiceConnectorConfig.PoolConfig poolConfig = new PooledServiceConnectorConfig.PoolConfig(20, 300, 30000);
DataSourceConfig dbConfig = new DataSourceConfig(poolConfig, null);
return connectionFactory().dataSource(dbConfig);
}
}

Related

Enforce Spring Boot Application to Fail When Cannot Connect to Kafka

I want to make my spring boot application fail on start if it cannot connect to the kafka broker. My application is only publishing messages to topics. I added this line to my properties file but no luck so far spring.kafka.admin.fail-fast=true.
Addition on how to speed up fail-fast
TL;DR Spring Boot 2.4.5 auto configuration does not let you speed up fail-fast using env parameters. Add this to your #Configuration to get 10 seconds timeout:
#Bean
public KafkaAdmin kafkaAdmin(#Autowired KafkaProperties properties) {
KafkaAdmin kafkaAdmin = new KafkaAdmin(properties.buildAdminProperties());
kafkaAdmin.setFatalIfBrokerNotAvailable(properties.getAdmin().isFailFast());
/* speed up fail fast */
kafkaAdmin.setOperationTimeout(5);
kafkaAdmin.setCloseTimeout(5);
return kafkaAdmin;
}
More detailed answer
Fail-fast occurs when initialize() method of class org.springframework.kafka.core.KafkaAdmin is executed. This method may block:
If new topics are found, it blocks on topic creation for up to operationTimeout
If topic creation failed, it blocks on releasing resources for up to closeTimeout
By default those values are 30 and 10 seconds accordingly (hardcoded in the class mentioned above). You can redefine them using set methods: setOperationTimeout(int sec), setCloseTimeout(int sec).
What about Spring Boot? KafkaAdmin bean is created in class org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration. As you can guess, Spring Boot simply does not set timeouts:
#Bean
#ConditionalOnMissingBean
public KafkaAdmin kafkaAdmin() {
KafkaAdmin kafkaAdmin = new KafkaAdmin(this.properties.buildAdminProperties());
kafkaAdmin.setFatalIfBrokerNotAvailable(this.properties.getAdmin().isFailFast());
return kafkaAdmin;
}
fail-fast will only work if there is at least one NewTopic bean in the context (so the admin will try to check if the topic exists and create it if not).
#SpringBootApplication
public class So55177700Application {
public static void main(String[] args) {
SpringApplication.run(So55177700Application.class, args);
}
#Bean
public NewTopic topic() {
return new NewTopic("so55177700", 1, (short) 1);
}
}
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-03-15 09:42:49.555 ERROR 41793 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: Could not configure topics

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 is the Difference between spring.profiles.active=production vs spring.profiles.active=local

When I try to run an spring boot application.
There is a property available inapplication.properties file where it has the property spring.profiles.active=production.
While search the details about this property in web I got to know that spring.profiles.active=local.
Can anyone kindly explain these details?
Certain environment-specific choices made for development aren’t appropriate or won’t work when the application transitions from development to production.
Consider database configuration, for instance. In a development environment,
you’re likely to use an embedded database preloaded with test data like this:
#Bean(destroyMethod="shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
In a production setting,
you may want to retrieve a DataSource from your container using JNDI:
#Bean
public DataSource dataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
Starting with Spring 3.1 you can use profiles. Method-leve #Profile annotation works starting from Spring 3.2. In Spring 3.1 it's only class-level.
#Configuration
public class DataSourceConfig {
#Bean(destroyMethod="shutdown")
#Profile("development")
public DataSource embeddedDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
#Bean
#Profile("production")
public DataSource jndiDataSource() {
JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
jndiObjectFactoryBean.setJndiName("jdbc/myDS");
jndiObjectFactoryBean.setResourceRef(true);
jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
return (DataSource) jndiObjectFactoryBean.getObject();
}
}
Each of the DataSource beans is in a profile and will only be created if the prescribed profile is active. Any bean that isn’t given a profile will always be created, regardless of what profile is active.
You can give any logical names to your profiles.
You can use this property to let Spring know which profiles should be active ( to be used while starting application). For example, if you give it in application.properties or via argument -Dspring.profiles.active=prod; you tell Spring, to run under prod profile. Which means - Spring will look for "application-prod.yml" or "application-prod.properties"file and will load all properties under it.
You can also annotate bean (method or class) by #Profile("PROFILE_NAME") - this ensures, the bean is mapped to certain profile.
You can pass multiple profiles to spring.profiles.active.
More information in docs - https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

Why does Spring boot autoconfigure's feature overriding the profile mechanism?

This is the code where I created a H2 datasource. It should be available only when 'dev' profile is active.
#Bean
#Profile("dev")
public DataSource h2() {
return new EmbeddedDatabaseBuilder().setType(H2).build();
}
But when I boot the application without any profile set, the spring boot initialize the H2 ignoring the profile annotation. Here is the output messages of spring boot at startup:
No active profile set, falling back to default profiles: default
Starting embedded database: url='jdbc:h2:mem:testdb ...
The profile isn't being ignored and it isn't your DataSource bean that's being created. It's Spring Boot's DataSource bean that's configured by DataSourceAutoConfiguration. It's running because H2 is on the class path.
If you don't want a DataSource to be auto-configured (so that you only get one when the dev profile is active), then you should exclude DataSourceAutoConfiguration:
#SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Spring Boot + Mybatis #MapperScan and SqlSessionFactory

Im developing a new app using Spring Boot. I use Mybatis for persistance. Im using Java Config for everything I can.
I'm getting this exception when the app starts regarding creating my Mybatis mapper interface
exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
My Sring Boot application class is set up like this
#SpringBootApplication
#MapperScan("com.mydomain.admin.service.dao")
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
The Mybatis mapper interface class is set up like this
package com.mydomain.admin.service.dao;
public interface AdminClientDAO {
#Select("SELECT clientId, name, enabledFlag as enabled, dateAdded, dateUpdated as updateDate FROM client")
public List<Client> findAll();
}
my datasource is configured with spring boot. I've named the properties
spring.datasource.* so spring boot with auto-configure the data source
Now, Im wondering if Im assuming too much spring boot magic. I assumed that spring boot would configure the sqlSessionFactory because mybatis was in the classpath..
Many examples I see show configuring the sqlSessionFactory as a #Bean in the Java Config.. Is this the way it should be done is should spring boot be doing some magic and auto-config it?
I found my issue. I was missing mybatis-spring-boot-starter
I have
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
In class called Application.java which extends
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
And my Application.java is initialized in class which extends
org.springframework.boot.context.web.SpringBootServletInitializer
And the datasource works fine in my Spring-Boot Application.
Hope this helps somebody searching for Spring Boot, Mybatis and SQLSessionFactory with datasource in spring.datasource.*

Resources