[[apis]]
= Working with {data-store-name} APIs

Once the {data-store-name} Cache and Regions have been configured, they can be injected and used inside application objects.
This chapter describes the integration with Spring's Transaction Management functionality and DAO exception hierarchy.
This chapter also covers support for dependency injection of {data-store-name} managed objects.

[[apis:template]]
== GemfireTemplate

As with many other high-level abstractions provided by Spring, {sdg-name} provides a *template*
to simplify {data-store-name} data access operations. The class provides several methods containing common Region operations,
but also provides the capability to *execute* code against native {data-store-name} APIs without having to deal with
{data-store-name} checked exceptions by using a `GemfireCallback`.

The template class requires a {data-store-name} `Region`, and once configured, is thread-safe and is reusable
across multiple application classes:

[source,xml]
----
<bean id="gemfireTemplate" class="org.springframework.data.gemfire.GemfireTemplate" p:region-ref="SomeRegion"/>
----

Once the template is configured, a developer can use it alongside `GemfireCallback` to work directly with
the {data-store-name} `Region` without having to deal with checked exceptions, threading or resource management concerns:

[source,java]
----
template.execute(new GemfireCallback<Iterable<String>>() {

	public Iterable<String> doInGemfire(Region region)
	        throws GemFireCheckedException, GemFireException {

		Region<String, String> localRegion = (Region<String, String>) region;

		localRegion.put("1", "one");
		localRegion.put("3", "three");

		return localRegion.query("length < 5");
	}
});
----

For accessing the full power of the {data-store-name} query language, a developer can use the `find` and `findUnique`
methods, which, compared to the `query` method, can execute queries across multiple Regions, execute projections,
and the like.

The `find` method should be used when the query selects multiple items (through `SelectResults`) and the latter,
`findUnique`, as the name suggests, when only one object is returned.

[[apis:exception-translation]]
== Exception Translation

Using a new data access technology requires not only accommodating a new API but also handling exceptions
specific to that technology.

To accommodate the exception handling case, the _Spring Framework_ provides a technology agnostic and consistent
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#dao-exceptions[exception hierarchy]
that abstracts the application from proprietary, and usually "checked", exceptions to a set of focused runtime
exceptions.

As mentioned in _Spring Framework's_ documentation,
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#orm-exception-translation[Exception translation]
can be applied transparently to your Data Access Objects (DAO) through the use of the `@Repository` annotation and AOP
by defining a `PersistenceExceptionTranslationPostProcessor` bean. The same exception translation functionality
is enabled when using {data-store-name} as long as the `CacheFactoryBean` is declared, e.g. using either a `<gfe:cache/>`
or `<gfe:client-cache>` declaration, which acts as an exception translator and is automatically detected by
the Spring infrastructure and used accordingly.

[[apis:transaction-management]]
== Local, Cache Transaction Management

One of the most popular features of the _Spring Framework_ is
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction[Transaction Management].

If you are not familiar with Spring's transaction abstraction then we strongly recommend
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction-motivation[reading]
about _Spring's Transaction Management_ infrastructure as it offers a consistent _programming model_ that works
transparently across multiple APIs and can be configured either programmatically or declaratively
(the most popular choice).

For {data-store-name}, {sdg-name} provides a dedicated, per-cache, `PlatformTransactionManager` that,
once declared, allows Region operations to be executed atomically through Spring:

[source,xml]
----
<gfe:transaction-manager id="txManager" cache-ref="myCache"/>
----

NOTE: The example above can be simplified even further by eliminating the `cache-ref` attribute if the {data-store-name} cache
is defined under the default name, `gemfireCache`. As with the other {sdg-name} namespace elements,
if the cache bean name is not configured, the aforementioned naming convention will be used.
Additionally, the transaction manager name is "`gemfireTransactionManager`" if not explicitly specified.

Currently, {data-store-name} supports optimistic transactions with *read committed* isolation. Furthermore, to guarantee
this isolation, developers should avoid making *in-place* changes that manually modify values present in the cache.
To prevent this from happening, the transaction manager configures the cache to use *copy on read* semantics by default,
meaning a clone of the actual value is created each time a read is performed. This behavior can be disabled if needed
through the `copyOnRead` property.

For more information on the semantics and behavior of the underlying Geode transaction manager, please refer to the Geode
{x-data-store-javadoc}/org/apache/geode/cache/CacheTransactionManager.html[CacheTransactionManager Javadoc]
as well as the {x-data-store-docs}/developing/transactions/chapter_overview.html[documentation].

[[apis:global-transaction-management]]
== Global, JTA Transaction Management

It is also possible for {data-store-name} to participate in a Global, JTA based transaction, such as a transaction managed
by an Java EE Application Server (e.g. WebSphere Application Server, a.k.a. WAS) using Container Managed Transactions
(CMT) along with other JTA resources.

However, unlike many other JTA "compliant" resources (e.g. JMS Message Brokers like ActiveMQ), {data-store-name} is *not*
an XA compliant resource.  Therefore, {data-store-name} must be positioned as the "_Last Resource_" in a JTA transaction
(_prepare phase_) since it does not implement the 2-phase commit protocol, or rather does not handle
distributed transactions.

Many managed environments with CMT maintain support for "_Last Resource_", non-XA compliant resources in JTA transactions
though it is not actually required in the JTA spec.  More information on what a non-XA compliant, "_Last Resource_" means
can be found in Red Hat's https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/5/html/Administration_And_Configuration_Guide/lrco-overview.html[documentation].
In fact, Red Hat's JBoss project, https://narayana.io/[Narayana] is one such LGPL Open Source implementation.  _Narayana_
refers to this as "_Last Resource Commit Optimization_" (LRCO).  More details can be found
https://narayana.io//docs/project/index.html#d0e1859[here].

However, whether you are using {data-store-name} in a standalone environment with an Open Source JTA Transaction Management
implementation that supports "_Last Resource_", or a managed environment (e.g. Java EE AS such as WAS),
_Spring Data Geode_ has you covered.

There are a series of steps you must complete to properly use {data-store-name} as a "_Last Resource_" in a JTA transaction
involving more than 1 transactional resource.  Additionally, there can only be 1 non-XA compliant resource
(e.g. {data-store-name}) in such an arrangement.

1) First, you must complete Steps 1-4 in {data-store-name}'s documentation
https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].

NOTE: #1 above is independent of your Spring [Boot] and/or [Data for {data-store-name}] application
and must be completed successfully.

2) Referring to Step 5 in {data-store-name}'s https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation],
{sdg-name}'s Annotation support will attempt to set the `GemFireCache`, {x-data-store-javadoc}/org/apache/geode/cache/GemFireCache.html#setCopyOnRead-boolean-[`copyOnRead`]
property for you when using the `@EnableGemFireAsLastResource` annotation.

However, if SDG's auto-configuration is unsuccessful then you must explicitly set the `copy-on-read` attribute on the
`<gfe:cache>` or `<gfe:client-cache>` element in XML or the `copyOnRead` property of the SDG `CacheFactoryBean` class
in JavaConfig to *true*.  For example...

Peer Cache XML:

[source,xml]
----
<gfe:cache ... copy-on-read="true"/>
----

Peer Cache JavaConfig:

[source,java]
----
@Bean
CacheFactoryBean gemfireCache() {

  CacheFactoryBean gemfireCache = new CacheFactoryBean();

  gemfireCache.setClose(true);
  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}
----

Client Cache XML:

[source,xml]
----
<gfe:client-cache ... copy-on-read="true"/>
----

Client Cache JavaConfig:

[source,java]
----
@Bean
ClientCacheFactoryBean gemfireCache() {

  ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();

  gemfireCache.setClose(true);
  gemfireCache.setCopyOnRead(true);

  return gemfireCache;
}
----

NOTE: explicitly setting the `copy-on-read` attribute or optionally the `copyOnRead` property
really should not be necessary.

3) At this point, you *skip* Steps 6-8 in {data-store-name}'s https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[documentation]
and let _Spring Data Geode_ work its magic.  All you need do is annotate your Spring `@Configuration` class
with {sdg-name}'s *new* `@EnableGemFireAsLastResource` annotation and a combination of Spring's
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction[Transaction Management]
infrastructure and {sdg-name}'s `@EnableGemFireAsLastResource` configuration does the trick.

The configuration looks like this...

[source,java]
----
@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement(order = 1)
class GeodeConfiguration {

  ...
}
----

The only requirements are...

3.1) The `@EnableGemFireAsLastResource` annotation must be declared on the same Spring `@Configuration` class
where Spring's `@EnableTransactionManagement` annotation is also specified.

3.2) The `order` attribute of the `@EnableTransactionManagement` annotation must be explicitly set to an integer value
that is not `Integer.MAX_VALUE` or `Integer.MIN_VALUE` (defaults to `Integer.MAX_VALUE`).

Of course, hopefully you are aware that you also need to configure Spring's `JtaTransactionManager`
when using JTA Transactions like so..

[source,java]
----
@Bean
public JtaTransactionManager transactionManager(UserTransaction userTransaction) {

   JtaTransactionManager transactionManager = new JtaTransactionManager();

   transactionManager.setUserTransaction(userTransaction);

   return transactionManager;
}
----

NOTE: The configuration in section <<apis:transaction-management>> does *not* apply here.
The use of {sdg-name}'s `GemfireTransactionManager` is applicable only in "Local", Cache Transactions,
*not* "Global", JTA Transactions.  Therefore, you do *not* configure the SDG `GemfireTransactionManager` in this case.
You configure Spring's `JtaTransactionManager` as shown above.

For more details on using _Spring's Transaction Management_ with JTA,
see https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#transaction-application-server-integration[here].

Effectively, {sdg-name}'s `@EnableGemFireAsLastResource` annotation imports configuration containing 2 Aspect
bean definitions that handles the {data-store-name} `o.a.g.ra.GFConnectionFactory.getConnection()`
and `o.a.g.ra.GFConnection.close()` operations at the appropriate points during the transactional operation.

Specifically, the correct sequence of events are...

1. `jtaTransation.begin()`

2. `GFConnectionFactory.getConnection()`

3. Call the application's `@Transactional` service method

4. Either `jtaTransaction.commit()` or `jtaTransaction.rollback()`

5. Finally, `GFConnection.close()`

This is consistent with how you, as the application developer, would code this manually if you had to use the JTA API
+ {data-store-name} API yourself, as shown in the
{data-store-name} https://gemfire90.docs.pivotal.io/geode/developing/transactions/jca_adapter_example.html#concept_swv_z2p_wk[example].

Thankfully, Spring does the heavy lifting for you and all you need do after applying the appropriate configuration
(shown above) is...

[source,java]
----
@Service
class MyTransactionalService ... {

  @Transactional
  public <Return-Type> someTransactionalServiceMethod() {
    // perform business logic interacting with and accessing multiple JTA resources atomically, here
  }

  ...
}
----

#1 & #4 above are appropriately handled for you by Spring's JTA based `PlatformTransactionManager` once the
`@Transactional` boundary is entered by your application (i.e. when the `MyTransactionSerivce.someTransactionalServiceMethod()`
is called).

#2 & #3 are handled by {sdg-name}'s new Aspects enabled with the `@EnableGemFireAsLastResource` annotation.

#3 of course is the responsibility of your application.

Indeed, with the appropriate logging configured, you will see the correct sequence of events...

[source,xml]
----
2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Getting transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionAcquiringAspect - Acquiring {data-store-name} Connection
from {data-store-name} JCA ResourceAdapter registered at [gfe/jca]

2017-Jun-22 11:11:37 TRACE MessageService - PRODUCER [ Message :
[{ @type = example.app.domain.Message, id= MSG0000000000, message = SENT }],
JSON : [{"id":"MSG0000000000","message":"SENT"}] ]

2017-Jun-22 11:11:37 TRACE TransactionInterceptor - Completing transaction for [example.app.service.MessageService.send]

2017-Jun-22 11:11:37 TRACE GemFireAsLastResourceConnectionClosingAspect - Closed {data-store-name} Connection @ [Reference [...]]
----

For more details on using {data-store-name} in JTA transactions,
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html[here].

For more details on configuring {data-store-name} as a "_Last Resource_",
see https://gemfire90.docs.pivotal.io/geode/developing/transactions/JTA_transactions.html#concept_csy_vfb_wk[here].

:leveloffset: +1

include::{basedocdir}/reference/cq-container.adoc[]

:leveloffset: -1

[[apis:declarable]]
== Wiring `Declarable` Components

{data-store-name} XML configuration (usually referred to as `cache.xml`) allows *user* objects to be declared
as part of the configuration. Usually these objects are `CacheLoaders` or other pluggable callback components
supported by {data-store-name}. Using native {data-store-name} configuration, each user type declared through XML must implement
the `Declarable` interface, which allows arbitrary parameters to be passed to the declared class
through a `Properties` instance.

In this section, we describe how you can configure these pluggable components when defined in `cache.xml`
using Spring while keeping your Cache/Region configuration defined in `cache.xml`.  This allows your
pluggable components to focus on the application logic and not the location or creation of `DataSources`
or other collaborators.

However, if you are starting a green field project, it is recommended that you configure Cache, Region,
and other pluggable {data-store-name} components directly in Spring.  This avoids inheriting from the `Declarable` interface
or the base class presented in this section.

See the following sidebar for more information on this approach.

.Eliminate `Declarable` components
****
A developer can configure custom types entirely through Spring as mentioned in <<bootstrap:region>>.
That way, a developer does not have to implement the `Declarable` interface, and also benefits from
all the features of the Spring IoC container (not just dependency injection but also life-cycle
and instance management).
****

As an example of configuring a `Declarable` component using Spring, consider the following declaration
(taken from the `Declarable` {x-data-store-javadoc}/org/apache/geode/cache/Declarable.html[Javadoc]):

[source,xml]
----
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <parameter name="URL">
     <string>jdbc://12.34.56.78/mydb</string>
   </parameter>
</cache-loader>
----

To simplify the task of parsing, converting the parameters and initializing the object, {sdg-name} offers
a base class (`WiringDeclarableSupport`) that allows {data-store-name} user objects to be wired through a *template* bean definition
or, in case that is missing, perform auto-wiring through the Spring IoC container. To take advantage of this feature,
the user objects need to extend `WiringDeclarableSupport`, which automatically locates the declaring `BeanFactory`
and performs wiring as part of the initialization process.

.Why is a base class needed?
****
In the current {data-store-name} release there is no concept of an *object factory* and the types declared are instantiated
and used as is. In other words, there is no easy way to manage object creation outside {data-store-name}.
****

[[apis:declarable:template-wiring]]
=== Configuration using *template* bean definitions

When used, `WiringDeclarableSupport` tries to first locate an existing bean definition and use that
as the wiring template.  Unless specified, the component class name will be used as an implicit bean definition name.

Let's see how our `DBLoader` declaration would look in that case:

[source,java]
----
class DBLoader extends WiringDeclarableSupport implements CacheLoader {

  private DataSource dataSource;

  public void setDataSource(DataSource dataSource){
    this.dataSource = dataSource;
  }

  public Object load(LoaderHelper helper) { ... }
}
----

[source,xml]
----
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- no parameter is passed (use the bean's implicit name, which is the class name) -->
</cache-loader>
----

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

  <bean id="dataSource" ... />

  <!-- template bean definition -->
  <bean id="com.company.app.DBLoader" abstract="true" p:dataSource-ref="dataSource"/>
</beans>
----

In the scenario above, as no parameter was specified, a bean with the id/name `com.company.app.DBLoader` was used
as a template for wiring the instance created by {data-store-name}. For cases where the bean name uses a different convention,
one can pass in the `bean-name` parameter in the {data-store-name} configuration:

[source,xml]
----
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- pass the bean definition template name as parameter -->
   <parameter name="bean-name">
     <string>template-bean</string>
   </parameter>
</cache-loader>
----

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

  <bean id="dataSource" ... />

   <!-- template bean definition -->
   <bean id="template-bean" abstract="true" p:dataSource-ref="dataSource"/>

</beans>
----

NOTE: The *template* bean definitions do not have to be declared in XML.
Any format is allowed (Groovy, annotations, etc).

[[apis:declarable:autowiring]]
=== Configuration using auto-wiring and annotations

By default, if no bean definition is found, `WiringDeclarableSupport` will
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-autowire[autowire]
the declaring instance. This means that unless any dependency injection *metadata* is offered by the instance,
the container will find the object setters and try to automatically satisfy these dependencies.
However, a developer can also use JDK 5 annotations to provide additional information to the auto-wiring process.

TIP: We strongly recommend reading the dedicated
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-annotation-config[chapter]
in the Spring documentation for more information on the supported annotations and enabling factors.

For example, the hypothetical `DBLoader` declaration above can be injected with a Spring-configured `DataSource`
in the following way:

[source,java]
----
class DBLoader extends WiringDeclarableSupport implements CacheLoader {

  // use annotations to 'mark' the needed dependencies
  @javax.inject.Inject
  private DataSource dataSource;

  public Object load(LoaderHelper helper) { ... }
}
----

[source,xml]
----
<cache-loader>
   <class-name>com.company.app.DBLoader</class-name>
   <!-- no need to declare any parameters since the class is auto-wired -->
</cache-loader>
----

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
">

     <!-- enable annotation processing -->
     <context:annotation-config/>

</beans>
----

By using the JSR-330 annotations, the `CacheLoader` code has been simplified since the location and creation
of the `DataSource` has been externalized and the user code is concerned only with the loading process.
The `DataSource` might be transactional, created lazily, shared between multiple objects or retrieved from JNDI.
These aspects can easily be configured and changed through the Spring container without touching
the `DBLoader` code.

[[apis:spring-cache-abstraction]]
== Support for the Spring Cache Abstraction

{sdg-name} provides an implementation of the Spring
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#cache[Cache Abstraction]
to position {data-store-name} as a _caching provider_ in Spring's caching infrastructure.

To use {data-store-name} as a backing implementation, a "_caching provider_" _in Spring's Cache Abstraction_,
simply add `GemfireCacheManager` to your configuration:

[source,xml]
[subs="verbatim,attributes"]
----
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:gfe="{spring-data-schema-namespace}"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
    {spring-data-schema-namespace} {spring-data-schema-location}
">

  <!-- enable declarative caching -->
  <cache:annotation-driven/>

  <gfe:cache id="gemfire-cache"/>

  <!-- declare GemfireCacheManager; must have a bean ID of 'cacheManager' -->
  <bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager"
      p:cache-ref="gemfire-cache">

</beans>
----

NOTE: The `cache-ref` attribute on the `CacheManager` bean definition is not necessary if the default cache bean name
is used (i.e. "gemfireCache"), i.e. `<gfe:cache>` without an explicit ID.

When the `GemfireCacheManager` (Singleton) bean instance is declared and declarative caching is enabled
(either in XML with `<cache:annotation-driven/>` or in JavaConfig with Spring's `@EnableCaching` annotation),
the Spring caching annotations (e.g. `@Cacheable`) identify the "caches" that will cache data in-memory
using {data-store-name} Regions.

These caches (i.e. Regions) must exist before the caching annotations that use them otherwise an error will occur.

By way of example, suppose you have a Customer Service application with a `CustomerService` application component
that performs caching...

[source,java]
----
@Service
class CustomerService {

@Cacheable(cacheNames="Accounts", key="#customer.id")
Account createAccount(Customer customer) {
  ...
}
----

Then you will need the following config.

XML:

[source,xml]
[subs="verbatim,attributes"]
----
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:gfe="{spring-data-schema-namespace}"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
    {spring-data-schema-namespace} {spring-data-schema-location}
">

  <!-- enable declarative caching -->
  <cache:annotation-driven/>

  <bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager">

  <gfe:cache/>

  <gfe:partitioned-region id="accountsRegion" name="Accounts" persistent="true" ...>
    ...
  </gfe:partitioned-region>
</beans>
----

JavaConfig:

[source,java]
----
@Configuration
@EnableCaching
class ApplicationConfiguration {

  @Bean
  CacheFactoryBean gemfireCache() {
    return new CacheFactoryBean();
  }

  @Bean
  GemfireCacheManager cacheManager() {
    GemfireCacheManager cacheManager = GemfireCacheManager();
    cacheManager.setCache(gemfireCache());
    return cacheManager;
  }

  @Bean("Accounts")
  PartitionedRegionFactoryBean accountsRegion() {
    PartitionedRegionFactoryBean accounts = new PartitionedRegionFactoryBean();

    accounts.setCache(gemfireCache());
    accounts.setClose(false);
    accounts.setPersistent(true);

    return accounts;
  }
}
----

Of course, you are free to choose whatever Region type you like (e.g. REPLICATE, PARTITION, LOCAL, etc).

For more details on _Spring's Cache Abstraction_, again, please refer to the
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#cache[documentation].
