config: Exclude DataSourceAutoConfiguration and update tenant database connection URL in tenants.json.
This commit is contained in:
@@ -2,8 +2,9 @@ package com.magistr.app;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
@SpringBootApplication
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -5,16 +5,21 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Конфигурация мультитенантного DataSource.
|
||||
@@ -38,6 +43,7 @@ public class TenantDataSourceConfig implements WebMvcConfigurer {
|
||||
private String defaultDbPassword;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public TenantRoutingDataSource tenantRoutingDataSource() {
|
||||
TenantRoutingDataSource routingDataSource = new TenantRoutingDataSource();
|
||||
|
||||
@@ -45,7 +51,7 @@ public class TenantDataSourceConfig implements WebMvcConfigurer {
|
||||
List<TenantConfig> tenants = loadTenantsFromFile();
|
||||
|
||||
// Если нет тенантов и есть дефолтный datasource — создаём "default" тенант
|
||||
if (tenants.isEmpty() && !defaultDbUrl.isBlank()) {
|
||||
if (tenants.isEmpty() && defaultDbUrl != null && !defaultDbUrl.isBlank()) {
|
||||
TenantConfig defaultTenant = new TenantConfig(
|
||||
"Default", "default", defaultDbUrl, defaultDbUsername, defaultDbPassword
|
||||
);
|
||||
@@ -62,18 +68,44 @@ public class TenantDataSourceConfig implements WebMvcConfigurer {
|
||||
}
|
||||
}
|
||||
|
||||
if (tenants.isEmpty()) {
|
||||
log.warn("No tenants configured! Backend will fail on DB queries.");
|
||||
if (routingDataSource.getTenantConfigs().isEmpty()) {
|
||||
log.warn("=== НЕТ НАСТРОЕННЫХ ТЕНАНТОВ ===");
|
||||
log.warn("Backend запустится, но API не будет работать без подключения к БД.");
|
||||
log.warn("Добавьте тенант через POST /api/database/tenants или настройте tenants.json");
|
||||
}
|
||||
|
||||
return routingDataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource dataSource(TenantRoutingDataSource tenantRoutingDataSource) {
|
||||
return tenantRoutingDataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
|
||||
DataSource dataSource, EntityManagerFactoryBuilder builder) {
|
||||
|
||||
Map<String, String> jpaProps = new HashMap<>();
|
||||
jpaProps.put("hibernate.hbm2ddl.auto", "update");
|
||||
jpaProps.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
|
||||
|
||||
return builder
|
||||
.dataSource(dataSource)
|
||||
.packages("com.magistr.app.model")
|
||||
.persistenceUnit("default")
|
||||
.properties(jpaProps)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
|
||||
return new JpaTransactionManager(emf);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TenantInterceptor tenantInterceptor() {
|
||||
return new TenantInterceptor();
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -21,6 +22,13 @@ public class TenantRoutingDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
private final Map<String, TenantConfig> tenantConfigs = new ConcurrentHashMap<>();
|
||||
private final Map<Object, Object> dataSources = new ConcurrentHashMap<>();
|
||||
private boolean initialized = false;
|
||||
|
||||
public TenantRoutingDataSource() {
|
||||
// Устанавливаем пустой map чтобы afterPropertiesSet не падал
|
||||
setTargetDataSources(new HashMap<>());
|
||||
setLenientFallback(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
@@ -41,6 +49,7 @@ public class TenantRoutingDataSource extends AbstractRoutingDataSource {
|
||||
// Обновляем target data sources
|
||||
setTargetDataSources(dataSources);
|
||||
afterPropertiesSet();
|
||||
initialized = true;
|
||||
|
||||
log.info("Added tenant '{}' -> {}", domain, config.getUrl());
|
||||
}
|
||||
@@ -108,6 +117,10 @@ public class TenantRoutingDataSource extends AbstractRoutingDataSource {
|
||||
return tenantConfigs.containsKey(domain.toLowerCase());
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized && !dataSources.isEmpty();
|
||||
}
|
||||
|
||||
private HikariDataSource createDataSource(TenantConfig config) {
|
||||
HikariDataSource ds = new HikariDataSource();
|
||||
ds.setJdbcUrl(config.getUrl());
|
||||
@@ -119,6 +132,8 @@ public class TenantRoutingDataSource extends AbstractRoutingDataSource {
|
||||
ds.setConnectionTimeout(10000);
|
||||
ds.setIdleTimeout(300000);
|
||||
ds.setMaxLifetime(600000);
|
||||
// Не падать при инициализации если БД недоступна
|
||||
ds.setInitializationFailTimeout(-1);
|
||||
return ds;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
"name": "Default (dev)",
|
||||
"domain": "default",
|
||||
"url": "jdbc:postgresql://db:5432/app_db",
|
||||
"url": "jdbc:postgresql://192.168.1.87:5432/app_db",
|
||||
"username": "myuser",
|
||||
"password": "supersecretpassword"
|
||||
}
|
||||
]
|
||||
]
|
||||
Reference in New Issue
Block a user