Как динамически установить пространство ключей Spring Data Cassandra?

Мы используем Spring Boot 1.5.10 с Spring Data для Apache Cassandra, и это все работает хорошо.

У нас появилось новое требование, когда нам нужно подключиться к другому пространству ключей, пока служба запущена и работает.

С помощью Spring Cloud Config Server мы можем легко установить значение spring.data.cassandra.keyspace-name, однако мы не уверены, есть ли способ динамически переключать (заставлять) службу использовать это новое пространство ключей без необходимости перезапуска, если сначала ?

Любые идеи или предложения?


person ASC    schedule 12.02.2018    source источник


Ответы (2)


Использование @RefreshScope со свойствами/репозиториями не работает, так как пространство ключей привязано к bean-компоненту Cassandra Session.

Используя Spring Data Cassandra 1.5 с Spring Boot 1.5, у вас есть как минимум два варианта:

  1. Объявите @RefreshScope CassandraSessionFactoryBean, см. также CassandraDataAutoConfiguration. Это прервет все операции Cassandra при обновлении и заново создаст все зависимые компоненты.
  2. Прослушайте RefreshScopeRefreshedEvent и измените пространство клавиш через USE my-new-keyspace;. Этот подход является менее инвазивным и не прерывает выполнение запросов. Вы бы в основном использовали прослушиватель событий.

    @Component
    class MySessionRefresh {
    
      private final Session session;
      private final Environment environment;
    
      // omitted constructors for brevity
    
      @EventListener
      @Order(Ordered.LOWEST_PRECEDENCE)
      public void handle(RefreshScopeRefreshedEvent event) {
    
        String keyspace = environment.getProperty("spring.data.cassandra.keyspace-name");
        session.execute("USE " + keyspace + ";");
      }
    }
    

В Spring Data Cassandra 2 мы представили SessionFactory, предоставляющая AbstractRoutingSessionFactory для управляемой кодом маршрутизации вызовов CQL/сеанса.

person mp911de    schedule 14.02.2018
comment
спасибо за ваш очень подробный ответ Джон. Поскольку я раньше не работал с прослушивателями событий, я просто хочу задать дополнительный вопрос. Я действительно хочу использовать вариант 2 из-за того, что он менее инвазивен, однако я немного не понимаю, нужно ли мне создавать отдельный класс слушателя для кода, который вы уже предоставили? Мне не удалось найти никаких примеров использования RefreshEvent, так что здесь немного неясно :-) Я вижу, что @Component работает и что bean-компонент создан, однако я не могу запустить Метод обработки(). Ваше здоровье - person ASC; 15.02.2018
comment
Я не Джон. Наличие собственного класса инкапсулирует всю ответственность за изменение/обновление пространства ключей в одном классе, вы не смешиваете аспекты. Однако это формат, который лучше всего подходит здесь вместо создания класса конфигурации... - person mp911de; 15.02.2018
comment
Извиняюсь за то, что перепутал ваше имя Марк :-) Я согласен с вашими рассуждениями об инкапсуляции ответственности, проблема, с которой я сталкиваюсь, заключается в том, что метод handle() не вызывается, когда я вызываю конечную точку /refresh в службе. нужно где-то регистрировать обработчик событий (я так понял, что это делается автоматически)? - person ASC; 15.02.2018
comment
Ваше решение работает при использовании RefreshScopeRefreshedEvent вместо RefreshEvent. Если вы не против обновить свой ответ, я могу принять ваше решение как наиболее правильное. ваше здоровье - person ASC; 15.02.2018
comment
Извините за неудобства, я исправил ответ и обновил его до RefreshScopeRefreshedEvent. - person mp911de; 15.02.2018
comment
С помощью этого решения сначала я создал session.execute для создания нового пространства ключей, если оно не существует, а затем для выполнения использования. Но проблема здесь в том, что схемы из сущностей с аннотацией @Table автоматически не создаются в новом пространстве ключей. - person xmlParser; 24.01.2019

Да, вы можете использовать @RefreshScope аннотация для bean-компонентов, содержащих значение spring.data.cassandra.keyspace-name.

После изменения значения конфигурации через Spring Cloud Config Server вы должны выполнить POST на конечной точке /refresh вашего приложения.

Из Документация по облаку Spring:

Spring @Bean, помеченный как @RefreshScope, получит специальную обработку при изменении конфигурации. Это решает проблему bean-компонентов с отслеживанием состояния, конфигурация которых вводится только при инициализации. Например, если у DataSource есть открытые соединения, когда URL-адрес базы данных изменяется через среду, мы, вероятно, хотим, чтобы владельцы этих соединений могли завершить то, что они делают. Затем в следующий раз, когда кто-то заимствует соединение из пула, он получает соединение с новым URL.

Из класс RefreshScope javadoc:

Реализация Scope, позволяющая динамически обновлять bean-компоненты во время выполнения (см. refresh(String) и refreshAll()). Если bean-компонент обновляется, то при следующем доступе к bean-компоненту (т. е. при выполнении метода) создается новый экземпляр. Все методы жизненного цикла применяются к экземплярам компонента, поэтому любые обратные вызовы уничтожения, которые были зарегистрированы в фабрике компонентов, вызываются при ее обновлении, а затем обратные вызовы инициализации вызываются как обычно при создании нового экземпляра. Новый экземпляр компонента создается из исходного определения компонента, поэтому любое внешнее содержимое (заполнители свойств или выражения в строковых литералах) переоценивается при его создании.

person Ortomala Lokni    schedule 12.02.2018
comment
Это то, что мы делаем, но как только это новое пространство ключей установлено (после использования /refresh), ничто не запускает службу, чтобы начать использовать это новое пространство ключей. Я не уверен, возможно ли это, потому что я думаю, что необходим перезапуск, прежде чем служба переключится на это новое пространство ключей. - person ASC; 12.02.2018
comment
@ASC На какой компонент вы поместили аннотацию @RefreshScope? - person Ortomala Lokni; 12.02.2018
comment
Я поместил его в класс контроллера ( @RestController) - person ASC; 13.02.2018
comment
Вы должны попытаться поместить его в репозиторий. - person Ortomala Lokni; 13.02.2018
comment
Джон Блюм написал в Твиттере: «Вы можете установить пространство ключей один раз для запуска, а затем оно должно остаться прежним», что указывает на то, что то, что я пытаюсь сделать, невозможно. - person ASC; 13.02.2018
comment
Возможно, вам следует дождаться новой версии, по крайней мере, она работает для источников данных: stackoverflow.com/questions/46031944/ - person Ortomala Lokni; 13.02.2018