how does spring boot auto configure the driver of a special datasource? - spring-boot

Without spring boot ,we must specify the detail of a data source,right?
#Configuration
public class DataSourceConfig {
#Bean
public DataSource getDataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url("jdbc:h2:mem:test");
dataSourceBuilder.username("SA");
dataSourceBuilder.password("");
return dataSourceBuilder.build();
}
}
With spring boot,we even do not need do anything,I know spring boot will detect whether there is a jar contains a data source to decide create a data source bean or not.I see the source code from org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration :
#Configuration(proxyBeanMethods = false)
#Conditional(PooledDataSourceCondition.class)
#ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
#Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
But my question is how does spring boot know the driver class or url and else for every different database?I can not find any specification from spring-boot-autoconfigure-2.5.0.jar

From DataSource Configuration in the docs:
Spring Boot can deduce the JDBC driver class for most databases from the URL. If you need to specify a specific class, you can use the spring.datasource.driver-class-name property.
So start without configuring anything and just putting the JDBC driver on the classpath. If it would not work, you can manually configure it.

Related

Custom DataSource Spring boot

spring works well when we use the default datasource and ways we can use in-build spring jpa.
So currently what we do is the following
specify the config for DB in the application.properties
myapp.datasource.url=jdbc:mysql:thin:#localhost:1521:myschema
myapp.datasource.username=user
myapp.datasource.password=password
myapp.datasource.driver-class=com.mysql.cj.jdbc.Driver
Custom datasource
#ConfigurationProperties(prefix = "myapp.datasource")
#Bean
public DataSource mySqlDataSource()
{
return DataSourceBuilder.create().build();
}
We have the same application running for multiple clients. Problem is each client has their own DB schema.
So, the problem now is that we need to be able to serve each client but in order to do this, we need to create multiple datasources
for instance:
#ConfigurationProperties(prefix = "myapp.partner1.datasource")
#Bean
public DataSource mySqlDataSourcePartner1()
{
return DataSourceBuilder.create().build();
}
#ConfigurationProperties(prefix = "myapp.partner2.datasource")
#Bean
public DataSource mySqlDataSourcePartner2()
{
return DataSourceBuilder.create().build();
}
#ConfigurationProperties(prefix = "myapp.partner3.datasource")
#Bean
public DataSource mySqlDataSourcePartner3()
{
return DataSourceBuilder.create().build();
}
and so on...
Is there a generic and more efficient way of doing this? where if in future when a new partner is added we can just specify the config in application properties and get that working?
You can use Spring Boot Multi-tenancy model using a separate database for each client. You can save the database configuration in config-properties or database then depending upon the ClientId you can you the Datasource. You need to add Interceptor to intercept the Request and identify the tenant. Please refer to the below example
https://tech.asimio.net/2017/01/17/Multitenant-applications-using-Spring-Boot-JPA-Hibernate-and-Postgres.html
please check
https://github.com/sumanentc/multitenant

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?

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

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

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