Как обновить список настроенных источников данных при регистрации нового клиента? SpringBoot с соединителем MySQL

Я разрабатываю мультитенантное приложение (отдельная база данных для каждого арендатора), используя Spring-Boot и MySQL для базы данных. Вот несколько важных моментов в моем заявлении:

  • Существует основная база данных, в которой хранятся все данные об арендаторах.
  • При регистрации арендатора создается новая база данных и в нее добавляются необходимые таблицы.
  • Я реализовал динамическую маршрутизацию, используя AbstractRoutingDataSource.
public class TenantRoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return TenantContext.getCurrentTenant() != null ? TenantContext.getCurrentTenant() : "master";
    }
}

Это мой конфигурационный компонент DataSource.

@Configuration
public class DataSourceConfig {


    @Bean
    public DataSource dataSource() {
        TenantRoutingDataSource routingDataSource = new TenantRoutingDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        DriverManagerDataSource masterDataSource=new DriverManagerDataSource();
        masterDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        masterDataSource.setUrl("jdbc:mysql://localhost:3306/test3");
        masterDataSource.setUsername("root");
        masterDataSource.setPassword("your_new_password");
        dataSourceMap.put("master", masterDataSource);

        // Populate the map with DataSource for each tenant
        try{
            List<String> tenantNames = getTenantDatabases(masterDataSource);

            tenantNames.forEach((tenant) -> {
                DriverManagerDataSource dataSource = new DriverManagerDataSource();
                dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
                dataSource.setUrl("jdbc:mysql://localhost:3306/" + tenant);
                dataSource.setUsername("root");
                dataSource.setPassword("password");
                dataSourceMap.put(tenant, dataSource);
            });
            routingDataSource.setTargetDataSources(dataSourceMap);
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
        return routingDataSource;
    }
    public List<String> getTenantDatabases(DataSource dataSource) throws Exception {
        List<String> tenantDatabases = new ArrayList<>();
        try (Connection connection = dataSource.getConnection();
             Statement statement = connection.createStatement();
             ResultSet resultSet = statement.executeQuery("SELECT name FROM tenant_info")) {

            while (resultSet.next()) {
                tenantDatabases.add(resultSet.getString("name"));
            }
        }
        return tenantDatabases;
    }
}


ПРОБЛЕМА Моя проблема заключается в том, что компонент источника данных настраивается во время запуска приложения, и когда новый арендатор регистрируется во время выполнения, он не добавляется в настроенный источник данных. Мне нужно перезапустить приложение, чтобы это произошло. Есть ли решение, позволяющее добавить новый источник данных в существующий список источников данных?

Что я думал попробовать

  • Я планировал обновить ApplicationContext. Возможно ли это/желательно?

Если у вас есть другая стратегия, предложите ее.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ответ на свой вопрос нашла здесь. Также обратитесь к этому репозиторию

@Slf4j
@Configuration
public class MultiTenantManager {

    private final Map<Object, Object> tenantDataSources = new ConcurrentHashMap<>();
    private final DataSourceProperties properties;

    private Function<String, DataSourceProperties> tenantResolver;

    private AbstractRoutingDataSource multiTenantDataSource;

    public MultiTenantManager(DataSourceProperties properties) {
        this.properties = properties;
    }

    @Bean
    public DataSource dataSource() {

        multiTenantDataSource = new AbstractRoutingDataSource() {
            @Override
            protected Object determineCurrentLookupKey() {
                return currentTenant.get();
            }
        };
        multiTenantDataSource.setTargetDataSources(tenantDataSources);
        multiTenantDataSource.setDefaultTargetDataSource(defaultDataSource());
        multiTenantDataSource.afterPropertiesSet();
        return multiTenantDataSource;
    }

    public void addTenant(String tenantId, String url, String username, String password) throws SQLException {

        DataSource dataSource = DataSourceBuilder.create()
                .driverClassName(properties.getDriverClassName())
                .url(url)
                .username(username)
                .password(password)
                .build();

        // Check that new connection is 'live'. If not - throw exception
        try(Connection c = dataSource.getConnection()) {
            tenantDataSources.put(tenantId, dataSource);
            multiTenantDataSource.afterPropertiesSet();
            log.debug("[d] Tenant '{}' added.", tenantId);
        }
    }
}

В методе addTenat после добавления нового источника данных

multitenantDatasource.afterPropertiesSet()

метод вызывается для проверки общей конфигурации bean-компонентов и окончательной инициализации. Используя эту настройку, вы можете динамически добавлять новые источники данных.

Спасибо @Cepr0

@PeterJ Я отредактировал ответ, чтобы было ясно. Спасибо за предложение.

Hari Prasath V 30.08.2024 07:33

Другие вопросы по теме