Изменение значения @Bean во время выполнения в Java Spring Boot - PullRequest
0 голосов
/ 07 июня 2019

В Java с Spring Boot framework существует @Bean с именем DataSource, который используется для подключения к базе данных и используется другим @Bean с именем JdbcTemplate, который служит для выполнения действий надбаза данных.Но есть проблема: для этого @Bean DataSource, который служит для установления соединения с базой данных, требуется предварительно настроить свойства соединения (url, имя пользователя и пароль).@Bean DataSource должен начинаться со значения «пусто» или «по умолчанию» при запуске проекта, и во время выполнения он изменяет это значение.Я хочу, чтобы определенная конечная точка выполняла действие по изменению значения @Bean, чтобы быть более точным.А с изменением значения @Bean DataSource JdbcTemplate, следовательно, сможет выполнять действия в нескольких базах данных.

Некоторые детали:

  • Я уже оценил проблему использования нескольких баз данных, и в моем случае это будет необходимо.
  • Все подключаемые базы данных имеют одинаковую модель.
  • Не думаю, что мне нужноудалите и создайте еще один @Bean DataSource во время выполнения, возможно, просто переопределите значения @Bean, которые сам Spring Boot уже создает автоматически.
  • Я уже запустил @Bean DataSourceс "пустым" значением путем создания метода с аннотацией @Bean, который возвращает объект DataSource, который в буквальном смысле этого кода: DataSourceBuilder.build().create();.
  • Мой английский не очень хорош, так что если это не такочень понятно, извините.

DataSource @Bean код:

@Bean
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

Основной класс:

@SpringBootApplication(scanBasePackages = "br.com.b2code")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RunAdm extends SpringBootServletInitializer implements 
CommandLineRunner {

    public static final String URL_FRONTEND = "*";


    /**
     * Método main do módulo de Gestão.
     *
     * @param args argumentos de inicialização
     * @throws Exception uma exception genérica
     */
    public static void main(String[] args) throws Exception {
        SpringApplication.run(RunAdm.class, args);
    }

    @Override
    protected SpringApplicationBuilder 
    configure(SpringApplicationBuilder application) {
        return application.sources(RunAdm.class);
    }

    @Override
    public void run(String... args) throws Exception {
    }

}

Класс, иллюстрирующий, как я используюJdbcTemplate:

@Repository
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClienteQueryRepositoryImpl implements ClienteQueryRepository {

    private final @NonNull
    JdbcTemplate jdbc;

    @Override
    public List<Cliente> findAll() {
        return jdbc.query(ClienteQuerySQL.SELECT_ALL_CLIENTE_SQL, new ClienteRowMapper());
    }

}

1 Ответ

0 голосов
/ 07 июня 2019

Я думаю, что в качестве общего подхода вы могли бы рассмотреть шаблон проектирования прокси для фактической реализации источника данных.

Предположим, что DataSource - это интерфейс, который имеет метод getConnection по имени пользователя и паролю (другие методы на самом деле не важны, потому что этот ответ теоретический):

interface DataSource {
   Connection getConnection(String user, String password);
}

Теперь, чтобы поддерживать много баз данных, вы можете захотеть предоставить реализацию источника данных, который будет выступать в качестве прокси для других источников данных, которые будут созданы на лету (как вы говорите, при вызове конечной точки).

Вот пример:

public class MultiDBDatasource implements DataSource {
    private DataSourcesRegistry registry;

    public Connection getConnection(String user, String password) {
        UserAndPassword userAndPassword = new UserAndPassword(user, password);

        registry.get(userAndPassword);
    }
}


@Component
class DataSourcesRegistry {
   private Map<UserAndPassword, DataSource> map = ...
   public DataSource get(UserAndPassword a)  { 
         map.get(a); 
   }


   public void addDataSource(UserAndPassword cred, DataSource ds) {
      // add to Map 
      map.put(...)
   }
}


@Controller
class InvocationEndPoint {

    // injected by spring
    private DataSourcesRegistry registry;

    @PostMapping ... 
    public void addNewDB(params) {
         DataSource ds = createDS(params); // not spring based 
         UserAndPassword cred = createCred(params);
         registry.addDataSource(cred, ds);
    } 

}

Пара заметок:

  1. Вы должны "переопределить" bean-компонент DataSource, предлагаемый Spring - это можно сделать, определив свой собственный bean-компонент с таким же именем в вашей собственной конфигурации, который будет иметь приоритет над определением Spring.

  2. Spring не создаст динамический источник данных, он будет создан из «точки вызова» (в данном случае для краткости контроллер, в реальной жизни, вероятно, какой-то сервис). в любом случае, весной будет управляться только Реестр, а не источники данных.

    1. Имейте в виду, что этот подход очень высокого уровня, в реальной жизни вам придется подумать о:
      • Пул соединений
      • Замер
      • Поддержка транзакций
      • Многопоточный доступ и многое другое
...