Как реализовать GemFire CacheListener в Spring Boot с использованием Spring Boot для Pivotal GemFire Starter

#spring-boot #spring-data-gemfire

#spring-boot #spring-data-gemfire

Вопрос:

Могу ли я узнать, как реализовать GemFire / Geode CacheListener в моем приложении Spring Boot?

Я хочу обнаруживать удаление и обновлять в моем регионе «Люди». Я использую org.springframework.data:зависимость spring-data-gemfire в Maven. Нужно ли мне включать какие-либо аннотации?

 @SpringBootApplication  
@ClientCacheApplication(name = "AccessingDataGemFireApplication", logLevel = "error")
@EnableEntityDefinedRegions(basePackageClasses = People.class)
@EnableGemfireRepositories  
public class Application
{
....
}
  

Ответ №1:

По-видимому, в последней версии GA CacheListener по-прежнему отсутствует поддержка аннотаций для обратных вызовов GemFire ( CacheLoader , spring-data-gemfire и т.д.). Некоторое время назад для реализации этого улучшения был создан тикет JIRA SGF-453, вы можете добавить себя в качестве наблюдателя, чтобы получать обновления о ходе выполнения.

Однако вы можете вручную связать a CacheListener с регионом, используя cache-listener элемент xml, как показано в документации. Или, еще один вариант, вы можете настроить прослушиватель непосредственно через API с помощью RegionFactoryBean.setListeners .

В качестве примера следующий класс запускает локальный сервер GemFire со встроенным локатором, создает REPLICATED регион с именем People и связывает с ним пользовательский CacheListener , который в основном выводит сообщение каждый раз, когда создается или удаляется запись:

 @EnableLogging
@EnableStatistics
@SpringBootApplication
@CacheServerApplication
public class GemFireServerApplication {

  public static void main(String[] args) {
    SpringApplication.run(GemFireServerApplication.class, args);
  }

  @EnableLocator
  @Profile("!clustered")
  @EnableManager(start = true)
  @Configuration
  static class LonerConfiguration { }

  @Bean("People")
  public ReplicatedRegionFactoryBean<?, ?> replicatedRegion(GemFireCache gemfireCache) {
    ReplicatedRegionFactoryBean<?, ?> replicatedRegion = new ReplicatedRegionFactoryBean<>();
    replicatedRegion.setCache(gemfireCache);
    replicatedRegion.setClose(false);
    replicatedRegion.setPersistent(false);
    replicatedRegion.setCacheListeners(new CacheListener[] { myCacheListener() });

    return replicatedRegion;
  }

  @Bean
  public CacheListener<?, ?> myCacheListener() {
    return new CacheListenerAdapter<String, String>() {
      @Override
      public void afterDestroy(EntryEvent<String, String> event) {
        System.out.println(String.format("AfterDestroy invoked for key %s !", event.getKey()));
        super.afterDestroy(event);
      }

      @Override
      public void afterCreate(EntryEvent<String, String> event) {
        System.out.println(String.format("AfterCreate invoked for key %s !", event.getKey()));
        super.afterCreate(event);
      }
    };
  }
}
  

Надеюсь, это поможет. Приветствия.

Ответ №2:

Поскольку вы используете более удобную @EnableEntityDefinedRegions аннотацию SDG (которая рекомендуется, особенно для простого UC), то вы явно не определяете определение компонента Region (например, используя ReplicationRegionFactoryBean или PartitionedRegionFactoryBean классы SDG), как это сделал Хуан Рамос в своем ответе.

В этом случае вы можете объявить a RegionConfigurer для изменения региона «Люди», а затем применить ту же технику, которую Хуан использовал в своем ответе, для предоставления CacheListener .

Например:

 @SpringBootApplication
@EnableEntityDefinedRegions(basePackageClasses = People.class)
@EnableGemfireRepositories(..)
class MySpringBootGemFireApplication {

  @Bean
  RegionConfigurer peopleRegionConfigurer(
      CacheListener<Long, Person> peopleRegionListener) {

    return new RegionConfigurer() {

      @Override
      public void configure(String beanName, 
          ClientRegionFactoryBean<Long, Person> regionFactory) {

        regionFactoryBean.setCacheListeners(
          new CacheListener[] { peopleRegionListener });
    };
  }

  @Bean
  CacheListenerAdapter<Long, Person> peopleRegionListener() {

    return new CacheListenerAdapter<>() {

        public void afterDestroy(EntryEvent<Long, Person> event) { ... }

        public void afterUpdate(EntryEvent<Long, Person> event) { ... }
    };
  }
}
  

ПРИМЕЧАНИЕ: при использовании Spring Boot, GemFire Starter ( org.springframework.geode:spring-gemfire-starter ), @ClientCacheApplication аннотация определенно не требуется, поскольку SBDG автоматически настраивает ClientCache экземпляр по умолчанию (см. Здесь).

Примечание: Кроме того, если ваше приложение GemfireRepositories находится в подпакете ниже основного класса Spring Boot application, вам также не нужно явно объявлять @EnableGemfireRepositories , поскольку SBDG автоматически настраивает инфраструктуру хранилища SD для вас (см. Здесь).

Для получения дополнительной информации о конфигураторах SDG смотрите здесь.

Надеюсь, это поможет.

Комментарии:

1. Когда я попробовал ваше решение, мой компилятор выдал мне следующее: «Целевой тип этого выражения должен быть функциональным интерфейсом» в строке «return (beanName, regionFactoryBean)». Поскольку это метод по умолчанию. Я думаю, что лямбды не позволяют переопределять методы по умолчанию. Есть ли способ решить эту проблему?

2. Приношу свои извинения. На самом деле, это потому, что RegionConfigurer интерфейс ( docs.spring.io/spring-data/geode/docs/current/api/org / … ) не является FunctionalInterface . Интерфейс определяет 2 метода по умолчанию, 1 с ClientRegionFactoryBean для определения клиентских регионов, а другой с PeerRegionFactoryBean при определении серверных регионов. Следовательно, вы должны точно указывать, какой метод вы «переопределяете», и поэтому _Lambda) не работает для этого интерфейса в отличие от других предоставляемых SDG Configurers .

3. Я исправил свой пример выше. Вы можете увидеть другой пример RegionConfigurer из набора тестов SDG, здесь ( github.com/spring-projects/spring-data-geode/blob/master/src / … ). Технически вам нужно переопределить только 1 из 2 методов в зависимости от того, является ли ваше приложение «клиентом» или фактическим «одноранговым узлом» в кластере. Учитывая, что вы используете @ClientCacheApplication , вам следует переопределить метод client, как показано в моем измененном примере выше.

4. Большое вам спасибо.