From 7d7f8a34dfaae71f38798e6ca9f9e4df3b3ad140 Mon Sep 17 00:00:00 2001 From: John Blum Date: Tue, 16 Apr 2019 12:20:28 -0700 Subject: [PATCH] Add Region Template auto-configuration documentation to Reference Docs. Resolves gh-31. --- .../src/docs/asciidoc/index.adoc | 1 + .../src/docs/asciidoc/templates.adoc | 276 ++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 spring-geode-docs/src/docs/asciidoc/templates.adoc diff --git a/spring-geode-docs/src/docs/asciidoc/index.adoc b/spring-geode-docs/src/docs/asciidoc/index.adoc index 35929f5e..45685838 100644 --- a/spring-geode-docs/src/docs/asciidoc/index.adoc +++ b/spring-geode-docs/src/docs/asciidoc/index.adoc @@ -209,6 +209,7 @@ endif::[] include::clientcache-applications.adoc[] include::configuration.adoc[] include::caching.adoc[] +include::templates.adoc[] include::repositories.adoc[] include::functions.adoc[] include::continuous-query.adoc[] diff --git a/spring-geode-docs/src/docs/asciidoc/templates.adoc b/spring-geode-docs/src/docs/asciidoc/templates.adoc new file mode 100644 index 00000000..60e318a2 --- /dev/null +++ b/spring-geode-docs/src/docs/asciidoc/templates.adoc @@ -0,0 +1,276 @@ +[[geode-data-access-region-templates]] +== Data Access with Region Templates + +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 convenient abstraction, you give up +flexibility and power 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] +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 of "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. + +[[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 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 <> 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. + +[[geode-data-access-region-templates-native-defined]] +=== Native-defined Regions + +SBDG will even auto-configure `GemfireTemplate` beans for Regions defined using Apache Geode/Pivotal GemFire native +configuration meta-data, such as `cache.xml`. + +Given the following GemFire/Geode native `cache.xml`: + +[source,xml] +---- + + + + + + +---- + +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.