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

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

Related

springboot spring datasource tomcat properties not working

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

Setting up in-memory H2 database without Spring Boot

I am working in a spring 5 (Not Sprig Boot) project. I need to test my application with in-memory H2 database. I am using Spring with Java Config on maven build tool. Is there any way I can configure in-memory H2 DB?
Usually I use this in my #Config class:
#Bean
public DataSource h2TestDataSource(){
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
So I use Spring Embedded DB in my spring projects (I don't use spring boot)
I hope it's useful.
You can add the DataSource bean using the EmbeddedDatabaseBuilder as follows:
#Bean
public DataSource dataSource(
#Value("${datasource.dbname}") String dbname,
#Value("${datasource.script}") String script) {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName(dbname)
.addScript(script)
.build();
}
application.properties
datasource.dbname=users
datasource.script=classpath:resources/users.sql
Also you can register h2-console servlet in the application configuration class as follows:
#Configuration
public class WebAppConfig implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) {
. . .
servletContext
.addServlet("H2Console", WebServlet.class)
.addMapping("/console/*");
. . .
}
}
Then you can open http://localhost:8080/console and connect to the jdbc:h2:mem:users database as follows:
See also How to enable h2-console in spring-webmvc without spring-boot?

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.*

Spring Boot : PropertySourcesPlaceholderConfigurer is not loading system properties

I have a Spring Boot application as follows:
#SpringBootApplication
#PropertySource(ignoreResourceNotFound=true,value={"classpath:application.properties","classpath:util-${spring.profiles.active}.properties"})
#ComponentScan("com.jmarts")
#EnableTransactionManagement
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilderconfigure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
I'm making use of spring profiles and based on active profile, a the correct environment specific file is loaded: utils-local.properties, utils-dev.properties, etc...
When profile is set through application.properties (spring), e.g. spring.profiles.active=local all works great, correct file (utils-local.properties)is loaded.
Providing profile through -D (gradle bootRun -Dspring.profiles.active=local) doesn't load profile. I was able to verify that the system properties is passed (print systemProperties)
I assume spring boot will register a PropertySourcesPlaceholderConfigurer if none is configured.
spring boot officially supports profile-specific properties using the naming convention application-{profile}.properties.
so you can remove "classpath:util-${spring.profiles.active}.properties" and add application-local.properties, application-dev.properties and so on in the classpath.

Hibernate Envers with Spring Boot - configuration

I'm trying to setup Hibernate Envers to work with my Spring Boot application.
I've included the Envers dependency and added #Audited annotations and it works fine, but I'm unable to configure specific Envers properties, Spring Boot doesn't seem to pick them up.
Specifically, I've tried to set the different db schema for audit tables by putting these to application.properties, but without luck:
hibernate.envers.default_schema=app_audit
or
org.hibernate.envers.default_schema=app_audit
or
spring.jpa.hibernate.envers.default_schema=app_audit
Neither of these work. Does anyone know how to set these?
EDIT.
As M. Deinum suggested I tried:
spring.jpa.properties.org.hibernate.envers.default_schema=app_audit
and it worked!
For all those configuration settings that aren't by default available you can specify them by simply prefixing them with spring.jpa.properties. Those properties will be added, as is, to the EntityManagerFactory (as JPA Properties).
spring.jpa.properties.org.hibernate.envers.default_schema=app_audit
Adding the above to the application.properties will add the properties and should configure Hibernate Envers.
This is also documented in the Spring Boot reference guide.
Links
Configure JPA properties
Envers Properties
Looking through the HibernateJpaAutoConfiguration class I can't see any support for envers properties. The following might not be the best solution but nevertheless your can give it a try.
In order to have Spring Boot support the envers properties you have to:
override the current AutoConfiguration class that Spring Boot uses to configure the Hibernate properties, so it will read the envers properties from your property files.
This will read the spring.jpa.hibernate.envers.default_schema from your file and add it to the properties of the entityManagerFactoryBean:
#Configuration
public class HibernateEnversAutoConfiguration extends HibernateJpaAutoConfiguration {
private RelaxedPropertyResolver environment;
public HibernateEnversAutoConfiguration() {
this.environment = null;
}
#Override
public void setEnvironment(Environment environment) {
super.setEnvironment(environment);
this.environment = new RelaxedPropertyResolver(environment, "spring.jpa.hibernate.");
}
#Override
protected void configure(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
super.configure(entityManagerFactoryBean);
Map<String, Object> properties = entityManagerFactoryBean.getJpaPropertyMap();
properties.put("hibernate.envers.default_schema", this.environment.getProperty("envers.default_schema"));
}
}
exclude the original HibernateJpaAutoConfiguration that Spring Boot uses and add your own as a bean so it will be replaced:
#EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
#EnableJpaRepositories(basePackages = "com.gabrielruiu.test")
#EntityScan(basePackages = "com.gabrielruiu.test")
#ComponentScan(basePackages = "com.gabrielruiu.test")
#Configuration
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
#Bean
public HibernateEnversAutoConfiguration hibernateEnversAutoConfiguration() {
return new HibernateEnversAutoConfiguration();
}
}
For those using MySQL and Spring Boot, the suggestion of using:
spring.jpa.properties.org.hibernate.envers.default_schema=yourAuditSchema will not work.
Use this instead:
spring.jpa.properties.org.hibernate.envers.default_catalog=yourAuditSchema
I use with yaml format:
spring:
jpa:
properties:
org:
hibernate:
format_sql: false
envers:
audit_table_suffix: AUDIT
revision_field_name: NRO_ID_REVISAO_AUDITORIA
revision_type_field_name: TPO_REVISAO_AUDITORIA

Resources