291 lines
9.8 KiB
Plaintext
291 lines
9.8 KiB
Plaintext
[[geode-data-access-region-templates]]
|
|
== Data Access with GemfireTemplate
|
|
|
|
There are several ways to access data stored in Apache Geode.
|
|
|
|
For instance, developers may choose to use the {apache-geode-javadoc}/org/apache/geode/cache/Region.html[Region API]
|
|
directly. If developers are driven by the application's domain context, they might choose to leverage the power of
|
|
{spring-data-commons-docs-html}/#repositories[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 {spring-framework-javadoc}/org/springframework/jdbc/core/JdbcTemplate.html[JdbcTemplate]
|
|
and {spring-framework-javadoc}/org/springframework/jms/core/JmsTemplate.html[JmsTemplate], which are provided by
|
|
the core Spring Framework.
|
|
|
|
Other Spring Data modules, such as Spring Data Redis, offer the
|
|
https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html[RedisTemplate],
|
|
and Spring Data for Apache Geode/Pivotal GemFire (SDG) offers the
|
|
{spring-data-gemfire-javadoc}/org/springframework/data/gemfire/GemfireTemplate.html[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 {spring-framework-docs}/data-access.html#dao-exceptions[Exception Hierarchy].
|
|
3. Automatic enlistment in the presence of local, cache transactions.
|
|
4. Protection from {apache-geode-javadoc}/org/apache/geode/cache/Region.html[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.
|
|
|
|
[[geode-data-access-region-templates-explicit-declaration]]
|
|
=== Explicitly Declared Regions
|
|
|
|
Given an explicitly declared Region bean definition:
|
|
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
[source,java]
|
|
----
|
|
@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.
|
|
|
|
[[geode-data-access-region-templates-entity-defined]]
|
|
=== Entity-defined Regions
|
|
|
|
SBDG auto-configures `GemfireTemplate` beans for Entity-defined Regions.
|
|
|
|
Given the following entity class:
|
|
|
|
[source,java]
|
|
----
|
|
@Region("Customers")
|
|
class Customer {
|
|
...
|
|
}
|
|
----
|
|
|
|
And configuration:
|
|
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
[source,java]
|
|
----
|
|
@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.
|
|
|
|
[[geode-data-access-region-templates-caching-defined]]
|
|
=== Caching-defined Regions
|
|
|
|
SBDG auto-configures `GemfireTemplate` beans for Caching-defined Regions.
|
|
|
|
When you are using Spring Framework's {spring-framework-docs}/integration.html#cache[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 {spring-framework-docs}integration.html#cache-annotations[Caching Annotations] of your application service
|
|
components.
|
|
|
|
Fortunately, SBDG makes enabling and configuring caching easy and <<geode-caching-provider,automatic>> out-of-the-box.
|
|
|
|
Given a cacheable application service component:
|
|
|
|
[source,java]
|
|
----
|
|
@Service
|
|
class CacheableCustomerService {
|
|
|
|
@Bean
|
|
@Qualifier("customersByNameTemplate")
|
|
private GemfireTemplate customersByNameTemplate;
|
|
|
|
@Cacheable("CustomersByName")
|
|
public Customer findBy(String name) {
|
|
return toCustomer(customersByNameTemplate.query("name = " + name));
|
|
}
|
|
}
|
|
----
|
|
|
|
And configuration:
|
|
|
|
[source,java]
|
|
----
|
|
@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: 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.
|
|
|
|
[[geode-data-access-region-templates-native-defined]]
|
|
=== 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`:
|
|
|
|
[source,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:
|
|
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
[source,java]
|
|
----
|
|
@Service
|
|
class ExampleService {
|
|
|
|
@Autowired
|
|
@Qualifier("exampleTemplate")
|
|
private GemfireTemplate exampleTemplate;
|
|
|
|
}
|
|
----
|
|
|
|
The same rules as above apply when multiple Regions are present.
|
|
|
|
[[geode-data-access-region-templates-rules]]
|
|
=== 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:
|
|
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
[source,java]
|
|
----
|
|
@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:
|
|
|
|
[source,java]
|
|
----
|
|
@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: 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.
|