Skip to content

Commit

Permalink
use modernway to configure multi datasources (#1527)
Browse files Browse the repository at this point in the history
* use modernway to configure multi datasources

* fix : build issue
  • Loading branch information
rajadilipkolli authored Nov 22, 2024
1 parent e29ad56 commit 4f1f107
Show file tree
Hide file tree
Showing 17 changed files with 144 additions and 71 deletions.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "MultiDataSourceMultiTenancyApplicationTest",
"request": "launch",
"mainClass": "com.example.multitenancy.MultiDataSourceMultiTenancyApplicationTest",
"projectName": "multidatasource-multitenancy"
},
{
"type": "java",
"name": "Spring Boot-Application<boot-reactive-cache>",
Expand Down Expand Up @@ -153,6 +160,16 @@
"projectName": "boot-jndi-sample",
"args": "--spring.profiles.active=local",
"envFile": "${workspaceFolder}/.env"
},
{
"type": "java",
"name": "Spring Boot-Application<multidatasource-multitenancy>",
"request": "launch",
"cwd": "${workspaceFolder}",
"mainClass": "com.example.multitenancy.MultiDataSourceMultiTenancyApplication",
"projectName": "multidatasource-multitenancy",
"args": "",
"envFile": "${workspaceFolder}/.env"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.8'
services:

postgresqldb:
image: postgres:16.5-alpine
image: postgres:17.1-alpine
environment:
- POSTGRES_USER=appuser
- POSTGRES_PASSWORD=secret
Expand Down
4 changes: 2 additions & 2 deletions jpa/multitenancy/multidatasource-multitenancy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.6</version>
<version>3.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.multitenancy</groupId>
Expand All @@ -19,7 +19,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<java.version>21</java.version>
<springdoc-openapi.version>2.6.0</springdoc-openapi.version>
<springdoc-openapi.version>2.7.0-RC1</springdoc-openapi.version>

<project.testresult.directory>${project.build.directory}/test-results</project.testresult.directory>
<spotless.version>2.43.0</spotless.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

@SpringBootApplication
@EnableConfigurationProperties({ApplicationProperties.class})
public class Application {
public class MultiDataSourceMultiTenancyApplication {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
SpringApplication.run(MultiDataSourceMultiTenancyApplication.class, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {
class GlobalExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import io.swagger.v3.oas.annotations.servers.Server;
import org.springframework.context.annotation.Configuration;

@Configuration
@OpenAPIDefinition(info = @Info(title = "db", version = "v1"), servers = @Server(url = "/"))
public class SwaggerConfig {}
@Configuration(proxyBeanMethods = false)
@OpenAPIDefinition(
info = @Info(title = "multidatasource-multitenancy", version = "v1"),
servers = @Server(url = "/"))
class SwaggerConfig {}
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
package com.example.multitenancy.config;

import com.example.multitenancy.config.multitenant.MultiTenantInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
@Configuration(proxyBeanMethods = false)
class WebMvcConfig implements WebMvcConfigurer {

private final ApplicationProperties properties;
private final MultiTenantInterceptor multiTenantInterceptor;

WebMvcConfig(ApplicationProperties properties, MultiTenantInterceptor multiTenantInterceptor) {
this.properties = properties;
this.multiTenantInterceptor = multiTenantInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
public void addInterceptors(@NonNull InterceptorRegistry registry) {
registry.addInterceptor(multiTenantInterceptor);
}

@Override
public void addCorsMappings(CorsRegistry registry) {
public void addCorsMappings(@NonNull CorsRegistry registry) {
registry.addMapping(properties.getCors().getPathPattern())
.allowedMethods(properties.getCors().getAllowedMethods())
.allowedHeaders(properties.getCors().getAllowedHeaders())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.example.multitenancy.config.multitenant.TenantIdentifierResolver;
import com.example.multitenancy.primary.entities.PrimaryCustomer;
import com.example.multitenancy.primary.repositories.PrimaryCustomerRepository;
import com.example.multitenancy.utils.DatabaseType;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
Expand All @@ -21,17 +21,22 @@
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(
basePackages = "com.example.multitenancy.primary.repositories",
basePackageClasses = PrimaryCustomerRepository.class,
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager")
@RequiredArgsConstructor
public class PrimaryDataSourceConfiguration {

private final JpaProperties jpaProperties;
private final TenantIdentifierResolver tenantIdentifierResolver;

public PrimaryDataSourceConfiguration(
JpaProperties jpaProperties, TenantIdentifierResolver tenantIdentifierResolver) {
this.jpaProperties = jpaProperties;
this.tenantIdentifierResolver = tenantIdentifierResolver;
}

@Bean(name = "primaryEntityManagerFactory")
LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import com.example.multitenancy.config.multitenant.TenantIdentifierResolver;
import com.example.multitenancy.secondary.entities.SecondaryCustomer;
import com.example.multitenancy.secondary.repositories.SecondaryCustomerRepository;
import com.example.multitenancy.utils.DatabaseType;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
Expand All @@ -21,17 +22,23 @@
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@Configuration(proxyBeanMethods = false)
@EntityScan(basePackageClasses = SecondaryCustomer.class)
@EnableJpaRepositories(
basePackages = "com.example.multitenancy.secondary.repositories",
basePackageClasses = SecondaryCustomerRepository.class,
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager")
@RequiredArgsConstructor
public class SecondaryDataSourceConfiguration {

private final JpaProperties jpaProperties;
private final TenantIdentifierResolver tenantIdentifierResolver;

public SecondaryDataSourceConfiguration(
JpaProperties jpaProperties, TenantIdentifierResolver tenantIdentifierResolver) {
this.jpaProperties = jpaProperties;
this.tenantIdentifierResolver = tenantIdentifierResolver;
}

@Bean(name = "secondaryEntityManagerFactory")
LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(
EntityManagerFactoryBuilder builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
import liquibase.UpdateSummaryEnum;
import liquibase.UpdateSummaryOutputEnum;
import liquibase.integration.spring.SpringLiquibase;
import liquibase.ui.UIServiceEnum;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Configuration(proxyBeanMethods = false)
public class MultiDatasourceConfig {
Expand Down Expand Up @@ -58,7 +61,10 @@ DataSourceProperties secondaryDataSourceProperties() {
DataSource secondaryDataSource(
@Qualifier("secondaryDataSourceProperties")
DataSourceProperties secondaryDataSourceProperties) {
return secondaryDataSourceProperties.initializeDataSourceBuilder().build();
return secondaryDataSourceProperties
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}

@Bean
Expand All @@ -81,15 +87,21 @@ private SpringLiquibase springLiquibase(DataSource dataSource, LiquibaseProperti
liquibase.setDataSource(dataSource);
liquibase.setChangeLog(properties.getChangeLog());
liquibase.setClearCheckSums(properties.isClearChecksums());
liquibase.setContexts(properties.getContexts());
if (!CollectionUtils.isEmpty(properties.getContexts())) {
liquibase.setContexts(
StringUtils.collectionToCommaDelimitedString(properties.getContexts()));
}
liquibase.setDefaultSchema(properties.getDefaultSchema());
liquibase.setLiquibaseSchema(properties.getLiquibaseSchema());
liquibase.setLiquibaseTablespace(properties.getLiquibaseTablespace());
liquibase.setDatabaseChangeLogTable(properties.getDatabaseChangeLogTable());
liquibase.setDatabaseChangeLogLockTable(properties.getDatabaseChangeLogLockTable());
liquibase.setDropFirst(properties.isDropFirst());
liquibase.setShouldRun(properties.isEnabled());
liquibase.setLabelFilter(properties.getLabelFilter());
if (!CollectionUtils.isEmpty(properties.getLabelFilter())) {
liquibase.setLabelFilter(
StringUtils.collectionToCommaDelimitedString(properties.getLabelFilter()));
}
liquibase.setChangeLogParameters(properties.getParameters());
liquibase.setRollbackFile(properties.getRollbackFile());
liquibase.setTestRollbackOnUpdate(properties.isTestRollbackOnUpdate());
Expand All @@ -101,6 +113,9 @@ private SpringLiquibase springLiquibase(DataSource dataSource, LiquibaseProperti
liquibase.setShowSummaryOutput(
UpdateSummaryOutputEnum.valueOf(properties.getShowSummaryOutput().name()));
}
if (properties.getUiService() != null) {
liquibase.setUiService(UIServiceEnum.valueOf(properties.getUiService().name()));
}
return liquibase;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
spring.application.name=multidatasource-multitenancy
server.port=8080
server.shutdown=graceful
spring.main.allow-bean-definition-overriding=true
spring.jmx.enabled=false

################ Logging #####################
logging.file.name=logs/multidatasource-multitenancy.log
logging.file.name=logs/${spring.application.name}.log
logging.level.web=INFO
logging.level.sql=INFO
## To enable transaction details logging
Expand All @@ -20,7 +19,7 @@ management.endpoint.health.show-details=always
################ Database #####################
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.hibernate.ddl-auto=none
#spring.jpa.properties.hibernate.format_sql=true
#spring.jpa.properties.hibernate.hbm2ddl.auto=validate
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
Expand All @@ -30,6 +29,7 @@ spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch=true
spring.jpa.properties.hibernate.query.in_clause_parameter_padding=true
spring.jpa.properties.hibernate.query.plan_cache_max_size=4096
spring.jpa.properties.hibernate.connection.provider_disables_autocommit=true
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

Expand All @@ -38,12 +38,14 @@ datasource.primary.username=appuser
datasource.primary.password=secret
datasource.primary.driverClassName=org.postgresql.Driver
datasource.primary.configuration.auto-commit=false
datasource.primary.configuration.pool-name=primaryPool
datasource.primary.liquibase.change-log= classpath:/db/changelog/db.primary.changelog-master.yml
datasource.secondary.url=jdbc:postgresql://localhost:5432/secondary
datasource.secondary.username=appuser
datasource.secondary.password=secret
datasource.secondary.driverClassName=org.postgresql.Driver
datasource.secondary.hikari.auto-commit=false
datasource.secondary.hikari.pool-name=secondaryPool
datasource.secondary.liquibase.change-log= classpath:/db/changelog/db.secondary.changelog-master.yml

spring.mvc.problemdetails.enabled=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.23.xsd">
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.29.xsd">

<changeSet author="raja" id="createSequence-customers-sequence" runOnChange="true">
<preConditions onFail="MARK_RAN">
Expand Down Expand Up @@ -31,7 +31,7 @@
<column name="text" type="varchar(1024)">
<constraints nullable="false"/>
</column>
<column name="version" type="tinyint"/>
<column name="version" type="tinyint" defaultValue="0"/>
<column name="tenant" type="VARCHAR(255)">
<constraints nullable="false" primaryKey="true"/>
</column>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.multitenancy;

import com.example.multitenancy.common.ContainersConfiguration;
import com.example.multitenancy.utils.AppConstants;
import org.springframework.boot.SpringApplication;

class MultiDataSourceMultiTenancyApplicationTest {

public static void main(String[] args) {
SpringApplication.from(MultiDataSourceMultiTenancyApplication::main)
.with(ContainersConfiguration.class)
.withAdditionalProfiles(AppConstants.PROFILE_TEST)
.run(args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
import org.springframework.test.web.servlet.MockMvc;

@ActiveProfiles({PROFILE_TEST})
@SpringBootTest(webEnvironment = RANDOM_PORT)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ContainersConfiguration.class)
@AutoConfigureMockMvc
public abstract class AbstractIntegrationTest extends DBContainerInitializer {
public abstract class AbstractIntegrationTest {

@Autowired protected MockMvc mockMvc;

Expand Down
Loading

0 comments on commit 4f1f107

Please sign in to comment.