9. Data Access with GemfireTemplate

There are several ways to access data stored in Apache Geode.

For instance, developers may choose to use the Region API directly. If developers are driven by the application’s domain context, they might choose to leverage the power of Spring Data Repositories instead.

While using the Region API directly offers flexibility, it couples your application to Apache Geode, which is usually undesirable and unnecessary. While using Spring Data Repositories provides a very powerful and convenient abstraction, you give up flexibility provided by a lower level API.

A good comprise is to use the Template pattern. Indeed, this pattern is consistently and widely used throughout the entire Spring portfolio.

For example, there is the JdbcTemplate and JmsTemplate, which are provided by the core Spring Framework.

Other Spring Data modules, such as Spring Data Redis, offer the RedisTemplate, and Spring Data for Apache Geode/Pivotal GemFire (SDG) offers the GemfireTemplate.

The GemfireTemplate provides a highly consistent and familiar API to perform data access operations on Apache Geode or Pivotal GemFire cache Regions.

GemfireTemplate offers:

  1. Simple, consistent and convenient data access API to perform CRUD and basic query operations on cache Regions.
  2. Use of Spring Framework’s consistent, data access Exception Hierarchy.
  3. Automatic enlistment in the presence of local, cache transactions.
  4. Protection from Region API breaking changes.

Given these conveniences, Spring Boot for Apache Geode & Pivotal GemFire (SBDG) will auto-configure GemfireTemplate beans for each Region present in the GemFire/Geode cache.

Additionally, SBDG is careful not to create a GemfireTemplate if the user has already declared a GemfireTemplate bean in the Spring ApplicationContext for a given Region.

9.1 Explicitly Declared Regions

Given an explicitly declared Region bean definition:

@Configuration
class GemFireConfiguration {

  @Bean("Example")
  ClientRegionFactoryBean<?, ?> exampleRegion (GemFireCache gemfireCache) {
    ...
  }
}

SBDG will automatically create a GemfireTemplate bean for the "Example" Region using a bean name "exampleTemplate". SBDG will name the GemfireTemplate bean after the Region by converting the first letter in the Region’s name to lowercase and appending the word "Template" to the bean name.

In a managed Data Access Object (DAO), I can inject the Template, like so:

@Repository
class ExampleDataAccessObject {

  @Autowired
  @Qualifier("exampleTemplate")
  private GemfireTemplate exampleTemplate;

}

It’s advisable, especially if you have more than 1 Region, to use the @Qualifier annotation to qualify which GemfireTemplate bean you are specifically referring as demonstrated above.

9.2 Entity-defined Regions

SBDG auto-configures GemfireTemplate beans for Entity-defined Regions.

Given the following entity class:

@Region("Customers")
class Customer {
  ...
}

And configuration:

@Configuration
@EnableEntityDefinedRegions(basePackageClasses = Customer.class}
class GemFireConfiguration {
  ...
}

SBDG auto-configures a GemfireTemplate bean for the "Customers" Region named "customersTemplate", which you can then inject into an application component:

@Service
class CustomerService {

  @Bean
  @Qualifier("customersTemplate")
  private GemfireTemplate customersTemplate;

}

Again, be careful to qualify the GemfireTemplate bean injection if you have multiple Regions, whether declared explicitly or implicitly, such as when using the @EnableEntityDefineRegions annotation.

9.3 Caching-defined Regions

SBDG auto-configures GemfireTemplate beans for Caching-defined Regions.

When you are using Spring Framework’s Cache Abstraction backed by either Apache Geode or Pivotal GemFire, 1 of the requirements is to configure Regions for each of the caches specified in the Caching Annotations of your application service components.

Fortunately, SBDG makes enabling and configuring caching easy and automatic out-of-the-box.

Given a cacheable application service component:

@Service
class CacheableCustomerService {

  @Bean
  @Qualifier("customersByNameTemplate")
  private GemfireTemplate customersByNameTemplate;

  @Cacheable("CustomersByName")
  public Customer findBy(String name) {
    return toCustomer(customersByNameTemplate.query("name = " + name));
  }
}

And configuration:

@Configuration
@EnableCachingDefinedRegions
class GemFireConfiguration {

  @Bean
  public CustomerService customerService() {
    return new CustomerService();
  }
}

SBDG auto-configures a GemfireTemplate bean named "customersByNameTemplate" used to perform data access operations on the "CustomersByName" (@Cacheable) Region, which you can inject into any managed application component, as shown above.

Again, be careful to qualify the GemfireTemplate bean injection if you have multiple Regions, whether declared explicitly or implicitly, such as when using the @EnableCachingDefineRegions annotation.

[Warning]Warning

There are certain cases where autowiring (i.e. injecting) GemfireTemplate beans auto-configured by SBDG for Caching-defined Regions into your application components will not always work! This has to do with the Spring Container bean creation process. In those case you may need to lazily lookup the GemfireTemplate as needed, using applicationContext.getBean("customersByNameTemplate", GemfireTemplate.class). This is certainly not ideal but works when autowiring does not.

9.4 Native-defined Regions

SBDG will even auto-configure GemfireTemplate beans for Regions defined using Apache Geode and Pivotal GemFire native configuration meta-data, such as cache.xml.

Given the following GemFire/Geode native cache.xml:

<?xml version="1.0" encoding="UTF-8"?>
<client-cache xmlns="http://geode.apache.org/schema/cache"
			  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			  xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
			  version="1.0">

	<region name="Example" refid="LOCAL"/>

</client-cache>

And Spring configuration:

@Configuration
@EnableGemFireProperties(cacheXmlFile = "cache.xml")
class GemFireConfiguration {
  ...
}

SBDG will auto-configure a GemfireTemplate bean named "exampleTemplate" after the "Example" Region defined in cache.xml. This Template can be injected like any other Spring managed bean:

@Service
class ExampleService {

  @Autowired
  @Qualifier("exampleTemplate")
  private GemfireTemplate exampleTemplate;

}

The same rules as above apply when multiple Regions are present.

9.5 Template Creation Rules

Fortunately, SBDG is careful not to create a GemfireTemplate bean for a Region if a Template by the same name already exists. For example, if you defined and declared the following configuration:

@Configuration
@EnableEntityDefinedRegions(basePackageClasses = Customer.class)
class GemFireConfiguration {

  @Bean
  public GemfireTemplate customersTemplate(GemFireCache cache) {
    return new GemfireTemplate(cache.getRegion("/Customers");
  }
}

Using our same Customers class, as above:

@Region("Customers")
class Customer {
  ...
}

Because you explicitly defined the "customersTemplate" bean, SBDG will not create a Template for the "Customers" Region automatically. This applies regardless of how the Region was created, whether using @EnableEntityDefinedRegions, @EnableCachingDefinedRegions, declaring Regions explicitly or defining Regions natively.

Even if you name the Template differently from the Region for which the Template was configured, SBDG will conserve resources and not create the Template.

For example, suppose you named the GemfireTemplate bean, "vipCustomersTemplate", even though the Region name is "Customers", based on the @Region annotated Customer class, which specified Region "Customers".

With the following configuration, SBDG is still careful not to create the Template:

@Configuration
@EnableEntityDefinedRegions(basePackageClasses = Customer.class)
class GemFireConfiguration {

  @Bean
  public GemfireTemplate vipCustomersTemplate(GemFireCache cache) {
    return new GemfireTemplate(cache.getRegion("/Customers");
  }
}

SBDG identifies that your "vipCustomersTemplate" is the Template used with the "Customers" Region and SBDG will not create the "customersTemplate" bean, which would result in 2 GemfireTemplate beans for the same Region.

[Note]Note

The name of your Spring bean defined in JavaConfig is the name of the method if the Spring bean is not explicitly named using the name (or value) attribute of the @Bean annotation.