Add section detailing the differences between Auto-configuration and Annotation-based configuration.
Resolves gh-20.
This commit is contained in:
@@ -4,6 +4,9 @@
|
||||
The following appendices provide additional help while developing Spring Boot applications backed by Apache Geode
|
||||
or Pivotal GemFire.
|
||||
|
||||
:!sectnums:
|
||||
include::configuration-annotations.adoc[leveloffset=+1]
|
||||
|
||||
:!sectnums:
|
||||
include::configuration-properties.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
@@ -0,0 +1,387 @@
|
||||
[[geode-autoconfiguration-annotations]]
|
||||
== Auto-configuration vs. Annotation-based configuration
|
||||
|
||||
The question most often asked is, "_What Spring Data for Apache Geode/Pivotal GemFire annotations can I use,
|
||||
or must I use, when developing Apache Geode or Pivotal GemFire applications with Spring Boot?_"
|
||||
|
||||
This section will answer this question and more.
|
||||
|
||||
[[geode-autoconfiguration-annotations-background]]
|
||||
=== Background
|
||||
|
||||
To help answer this question, we must start by reviewing the complete collection of available
|
||||
Spring Data for Apache Geode/Pivotal GemFire (SDG) annotations. These annotations are provided in the
|
||||
{spring-data-geode-javadoc}/org/springframework/data/gemfire/config/annotation/package-summary.html[org.springframework.data.gemfire.config.annotation]
|
||||
package. Most of the pertinent annotations begin with `@Enable...`, except for the base annotations:
|
||||
`@ClientCacheApplication`, `@PeerCacheApplication` and `@CacheServerApplication`.
|
||||
|
||||
By extension, Spring Boot for Apache Geode/Pivotal GemFire (SBDG) builds on SDG's Annotation-based configuration model
|
||||
to implement _auto-configuration_ and apply Spring Boot's core concepts, like "_convention over configuration_",
|
||||
enabling GemFire/Geode applications to be built with Spring Boot reliably, quickly and easily.
|
||||
|
||||
SDG provides this Annotation-based configuration model to, first and foremost, give application developers "_choice_"
|
||||
when building Spring applications using either Apache Geode or Pivotal GemFire. SDG makes no assumptions about what
|
||||
application developers are trying to do and fails fast anytime the configuration is ambiguous, giving users immediate
|
||||
feedback.
|
||||
|
||||
Second, SDG's Annotations were meant to get application developers up and running quickly and reliably with ease. SDG
|
||||
accomplishes this by applying sensible defaults so application developers do not need to know, or even have to learn,
|
||||
all the intricate configuration details and tooling provided by GemFire/Geode to accomplish simple tasks,
|
||||
e.g. build a prototype.
|
||||
|
||||
So, SDG is all about "choice" and SBDG is all about "convention". Together these frameworks provide application
|
||||
developers with convenience and reliability to move quickly and easily.
|
||||
|
||||
To learn more about the motivation behind SDG's Annotation-based configuration model, refer to the
|
||||
{spring-data-gemfire-docs-html}/#bootstrap-annotation-config-introduction[Reference Documentation].
|
||||
|
||||
[[geode-autoconfiguration-annotations-conventions]]
|
||||
=== Conventions
|
||||
|
||||
Currently, SBDG provides _auto-configuration_ for the following features:
|
||||
|
||||
* `ClientCache`
|
||||
* Caching with Spring's Cache Abstraction
|
||||
* Continuous Query
|
||||
* Function Execution & Implementation
|
||||
* PDX
|
||||
* `GemfireTemplate`
|
||||
* Spring Data Repositories
|
||||
* Security (Client/Server Auth & SSL)
|
||||
* Spring Session
|
||||
|
||||
Technically, this means the following SDG Annotations are not required to use the features above:
|
||||
|
||||
* `@ClientCacheApplication`
|
||||
* `@EnableGemfireCaching` (or by using Spring Framework's `@EnableCaching`)
|
||||
* `@EnableContinuousQueries`
|
||||
* `@EnableGemfireFunctionExecutions`
|
||||
* `@EnableGemfireFunctions`
|
||||
* `@EnablePdx`
|
||||
* `@EnableGemfireRepositories`
|
||||
* `@EnableSecurity`
|
||||
* `@EnableSsl`
|
||||
* `@EnableGemFireHttpSession`
|
||||
|
||||
Since SBDG auto-configures these features for you, then the above annotations are not strictly required. Typically, you
|
||||
would only declare one of theses annotations when you want to "override" Spring Boot's conventions, expressed in
|
||||
_auto-configuration_, and "customize" the behavior of the feature.
|
||||
|
||||
[[geode-autoconfiguration-annotations-overriding]]
|
||||
=== Overriding
|
||||
|
||||
In this section, we cover a few examples to make the behavior when overriding more apparent.
|
||||
|
||||
[[geode-autoconfiguration-annotations-overriding-caches]]
|
||||
==== Caches
|
||||
|
||||
By default, SBDG provides you with a `ClientCache` instance. Technically, SBDG accomplishes this by annotating
|
||||
an auto-configuration class with `@ClientCacheApplication`, internally.
|
||||
|
||||
It is by convention that we assume most application developers' will be developing Spring Boot applications
|
||||
using Apache Geode or Pivotal GemFire as "client" applications in GemFire/Geode's client/server topology. This is
|
||||
especially true as users migrate their applications to a managed environment, such as Pivotal CloudFoundry (PCF)
|
||||
using Pivotal Cloud Cache (PCC).
|
||||
|
||||
Still, users are free to "override" the default settings and declare their Spring applications to be actual peer `Cache`
|
||||
members of a cluster, instead.
|
||||
|
||||
For example:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@CacheServerApplication
|
||||
class MySpringBootPeerCacheServerApplication { ... }
|
||||
----
|
||||
|
||||
By declaring the `@CacheServerApplication` annotation, you effectively override the SBDG default. Therefore, SBDG
|
||||
will not provide a `ClientCache` instance because you have informed SBDG of exactly what you want, i.e. a peer `Cache`
|
||||
instance hosting an embedded `CacheServer` that allows client connections.
|
||||
|
||||
However, you then might ask, "_Well, how do I customize the ClientCache instance when developing client applications
|
||||
without explicitly declaring the @ClientCacheApplication annotation, then?_"
|
||||
|
||||
First, you are entirely allowed to "customize" the `ClientCache` instance by explicitly declaring the
|
||||
`@ClientCacheApplication` annotation in your Spring Boot application configuration, and set specific attributes
|
||||
as needed. However, you should be aware that by explicitly declaring this annotation, or any of the other
|
||||
auto-configured annotations by default, then you assume all the responsibility that comes with it since you have
|
||||
effectively overridden the auto-configuration. One example of this is Security, which we touch on more below.
|
||||
|
||||
The most ideal way to "customize" the configuration of any feature is by way of the well-known and documented
|
||||
<<geode-configuration-metadata,Properties>>, specified in Spring Boot `application.properties` (the "convention"),
|
||||
or by using a {spring-data-gemfire-docs-html}/#bootstrap-annotation-config-configurers[Configurer].
|
||||
|
||||
See the <<geode-clientcache-applications,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-overriding-security]]
|
||||
==== Security
|
||||
|
||||
Like the `@ClientCacheApplication` annotation, the `@EnableSecurity` annotation is not strictly required, not unless
|
||||
you want to override and customize the defaults.
|
||||
|
||||
Outside a managed environment, the only Security configuration required is specifying a username and password. You do
|
||||
this using the well-known and document SDG username/password properties in Spring Boot `application.properties`,
|
||||
like so:
|
||||
|
||||
.Required Security Properties in a Non-Manage Envionment
|
||||
[source,properties]
|
||||
----
|
||||
spring.data.gemfire.security.username=MyUser
|
||||
spring.data.gemfire.security.password=Secret
|
||||
----
|
||||
|
||||
You do not need to explicitly declare the `@EnableSecurity` annotation just to specify Security configuration
|
||||
(e.g. username/password).
|
||||
|
||||
Inside a managed environment, such as Pivotal CloudFoundry (PCF) when using Pivotal Cloud Cache (PCC), SBDG is able to
|
||||
introspect the environment and configure Security (Auth) completely without the need to specify any configuration,
|
||||
usernames/passwords, or otherwise. This is due in part because PCF supplies the security details in the VCAP
|
||||
environment when the app is deployed to PCF and bound to services (e.g. PCC).
|
||||
|
||||
So, in short, you do not need to explicitly declare the `@EnableSecurity` annotation (or the `@ClientCacheApplication`
|
||||
for that matter).
|
||||
|
||||
However, if you do explicitly declare either the `@ClientCacheApplication` and/or `@EnableSecurity` annotations,
|
||||
guess what, you are now responsible for this configuration and SBDG's _auto-configuration_ no longer applies.
|
||||
|
||||
While explicitly declaring `@EnableSecurity` makes more sense when "overriding" the SBDG Security _auto-configuration_,
|
||||
explicitly declaring the `@ClientCacheApplication` annotation most likely makes less sense with regard to its impact
|
||||
on Security configuration.
|
||||
|
||||
This is entirely due to the internals of GemFire/Geode, which in certain cases, like Security, not even Spring
|
||||
is able to completely shield users from the nuances of GemFire/Geode's configuration.
|
||||
|
||||
Both Auth and SSL must be configured before the cache instance (whether a `ClientCache` or a peer `Cache`,
|
||||
it does not matter) is created. Technically, this is because Security is enabled/configured during the "construction"
|
||||
of the cache. And, the cache pulls the configuration from JVM System properties that must be set before the cache
|
||||
is constructed.
|
||||
|
||||
Structuring the "exact" order of the _auto-configuration_ classes provided by SBDG when the classes are triggered,
|
||||
is no small feat. Therefore, it should come as no surprise to learn that the Security _auto-configuration_ classes
|
||||
in SBDG must be triggered before the ClientCache _auto-configuration_ class, which is why a ClientCache instance cannot
|
||||
"auto" authenticate properly in PCC when the `@ClientCacheApplication` is explicitly declared without some assistance
|
||||
(i.e. you must also explicitly declare the `@EnableSecurity` annotation in this case since you overrode the
|
||||
_auto-configuration_ of the cache, and, well, implicitly Security as well).
|
||||
|
||||
Again, this is a GemFire/Geode limitation in how Security (Auth) and SSL meta-data is supplied to GemFire/Geode.
|
||||
|
||||
See the <<geode-security,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension]]
|
||||
=== Extension
|
||||
|
||||
Most of the time, many of the other auto-configured annotations for CQ, Functions, PDX, Repositories, and so on, do not
|
||||
need to ever be declared explicitly.
|
||||
|
||||
Many of these features are enabled automatically by having SBDG or other libraries (e.g. Spring Session)
|
||||
on the classpath, or are enabled based on other annotations applied to beans in the Spring `ApplicationContext`.
|
||||
|
||||
Let's review a few examples.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension-caching]]
|
||||
==== Caching
|
||||
|
||||
It is rarely, if ever, necessary to explicitly declare either the Spring Framework's `@EnableCaching`, or the SDG
|
||||
specific `@EnableGemfireCaching` annotation, in Spring configuration when using SBDG. SBDG automatically "enables"
|
||||
caching and configures the SDG `GemfireCacheManager` for you.
|
||||
|
||||
You simply only need to focus on which application service components are appropriate for caching:
|
||||
|
||||
.Service Caching
|
||||
[source,java]
|
||||
----
|
||||
@Service
|
||||
class CustomerService {
|
||||
|
||||
@Autowired
|
||||
private CustomerRepository customerRepository;
|
||||
|
||||
@Cacheable("CustomersByName")
|
||||
public Customer findBy(String name) {
|
||||
return customerRepository.findByName(name);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Of course, it is necessary to create GemFire/Geode Regions backing the caches declared in your application service
|
||||
components (e.g. "CustomersByName") using Spring's Caching Annotations (e.g. `@Cacheable), or alternatively,
|
||||
JSR-107, JCache annotations (e.g. `@CacheResult`).
|
||||
|
||||
You can do that by defining each Region explicitly, or more conveniently, you can simply use:
|
||||
|
||||
.Configuring Caches (Regions)
|
||||
[source,java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableCachingDefinedRegions
|
||||
class Application { ... }
|
||||
----
|
||||
|
||||
`@EnableCachingDefinedRegions` is optional, provided for convenience, and complimentary to caching when used
|
||||
rather than necessary.
|
||||
|
||||
See the <<geode-caching-provider,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension-cq]]
|
||||
==== Continuous Query
|
||||
|
||||
It is rarely, if ever, necessary to explicitly declare the SDG `@EnableContinuousQueries` annotation. Instead,
|
||||
you should be focused on defining your application queries and worrying less about the plumbing.
|
||||
|
||||
For example:
|
||||
|
||||
.Defining Queries for CQ
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class TemperatureMonitor extends AbstractTemperatureEventPublisher {
|
||||
|
||||
@ContinuousQuery(name = "BoilingTemperatureMonitor",
|
||||
query = "SELECT * FROM /TemperatureReadings WHERE temperature.measurement >= 212.0")
|
||||
public void boilingTemperatureReadings(CqEvent event) {
|
||||
publish(event, temperatureReading -> new BoilingTemperatureEvent(this, temperatureReading));
|
||||
}
|
||||
|
||||
@ContinuousQuery(name = "FreezingTemperatureMonitor",
|
||||
query = "SELECT * FROM /TemperatureReadings WHERE temperature.measurement <= 32.0")
|
||||
public void freezingTemperatureReadings(CqEvent event) {
|
||||
publish(event, temperatureReading -> new FreezingTemperatureEvent(this, temperatureReading));
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Of course, GemFire/Geode CQ only applies to clients.
|
||||
|
||||
See the <<geode-continuous-query,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension-functions]]
|
||||
==== Functions
|
||||
|
||||
It is rarely, if ever, necessary to explicitly declare either the `@EnableGemfireFunctionExecutions`
|
||||
or `@EnableGemfireFunctions` annotations. SBDG provides _auto-configuration_ for both Function implementations
|
||||
and executions. You simply need to define the implementation:
|
||||
|
||||
.Function Implementation
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
class GemFireFunctions {
|
||||
|
||||
@GemfireFunction
|
||||
Object exampleFunction(Object arg) {
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
And then define the execution:
|
||||
|
||||
.Function Execution
|
||||
[source,java]
|
||||
----
|
||||
@OnRegion(region = "Example")
|
||||
interface GemFireFunctionExecutions {
|
||||
|
||||
Object exampleFunction(Object arg);
|
||||
}
|
||||
----
|
||||
|
||||
SBDG will automatically find, configure and register Function Implementations (POJOs) in GemFire/Geode as proper
|
||||
`Functions` as well as create Executions proxies for the Interfaces which can then be injected into application service
|
||||
components to invoke the registered `Functions` without needing to explicitly declare the enabling annotations.
|
||||
The application Function Implementations & Executions (Interfaces) should simply exist below the `@SpringBootApplication`
|
||||
annotated main class.
|
||||
|
||||
See the <<[geode-functions,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension-pdx]]
|
||||
==== PDX
|
||||
|
||||
It is rarely, if ever, necessary to explicitly declare the `@EnablePdx` annotation since SBDG _auto-configures_ PDX
|
||||
by default. SBDG automatically configures the SDG `MappingPdxSerializer` as the default `PdxSerializer` as well.
|
||||
|
||||
It is easy to customize the PDX configuration by setting the appropriate <<geode-configuration-metadata,Properties>>
|
||||
(search for "PDX") in Spring Boot `application.properties`.
|
||||
|
||||
See the <<geode-data-serialization,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-extension-repositories]]
|
||||
==== Spring Data Repositories
|
||||
|
||||
It is rarely, if ever, necessary to explicitly declare the `@EnableGemfireRepositories` annotation since SBDG
|
||||
_auto-configures_ Spring Data (SD) _Repositories_ by default.
|
||||
|
||||
You simply only need to define your Repositories and get cranking:
|
||||
|
||||
.Customer's Repository
|
||||
[source,java]
|
||||
----
|
||||
interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||
|
||||
Customer findByName(String name);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
SBDG finds the _Repository_ interfaces defined in your application, proxies them, and registers them as beans
|
||||
in the Spring `ApplicationContext`. The _Repositories_ may be injected into other application service components.
|
||||
|
||||
It is sometimes convenient to use the `@EnableEntityDefinedRegions` along with SD _Repositories_ to identify
|
||||
the entities used by your application and define the Regions used by the SD _Repository_ infrastructure to persist
|
||||
the entity's state. The `@EnableEntityDefinedRegions` annotation is optional, provided for convenience,
|
||||
and complimentary to the `@EnableGemfireRepositories` annotation.
|
||||
|
||||
See the <<geode-repositories,Reference Guide>> for more details.
|
||||
|
||||
[[geode-autoconfiguration-annotations-explicit]]
|
||||
=== Explicit Configuration
|
||||
|
||||
Most of the other annotations provided in SDG are focused on particular application concerns, or enable certain
|
||||
GemFire/Geode features, rather than being a necessity.
|
||||
|
||||
A few examples include:
|
||||
|
||||
* `@EnableAutoRegionLookup`
|
||||
* `@EnableBeanFactoryLocator`
|
||||
* `@EnableCacheServer(s)`
|
||||
* `@EnableCachingDefinedRegions`
|
||||
* `@EnableClusterConfiguration`
|
||||
* `@EnableCompression`
|
||||
* `@EnableDiskStore(s)`
|
||||
* `@EnableEntityDefinedRegions`
|
||||
* `@EnableEviction`
|
||||
* `@EnableExpiration`
|
||||
* `@EnableGemFireAsLastResource`
|
||||
* `@EnableHttpService`
|
||||
* `@EnableIndexing`
|
||||
* `@EnableOffHeap`
|
||||
* `@EnableLocator`
|
||||
* `@EnableManager`
|
||||
* `@EnableMemcachedServer`
|
||||
* `@EnablePool(s)`
|
||||
* `@EnableRedisServer`
|
||||
* `@EnableStatistics`
|
||||
* `@UseGemFireProperties`
|
||||
|
||||
None of these annotations are necessary and none are auto-configured by SBDG. They are simply at the
|
||||
application developers disposal if and when needed. This also means none of these annotations are in conflict with
|
||||
any SBDG _auto-configuration_.
|
||||
|
||||
[[geode-autoconfiguration-annotations-summary]]
|
||||
=== Summary
|
||||
|
||||
In conclusion, it is important to understand where SDG ends and SBDG begins. It all begins with the _auto-configuration_
|
||||
provided by SBDG out-of-the-box.
|
||||
|
||||
If a feature is not covered by SBDG's _auto-configuration_, then you are responsible for enabling and configuring
|
||||
the feature appropriately, as needed by your application (e.g. `@EnableRedisServer`).
|
||||
|
||||
In other cases, you might also want to explicitly declare a complimentary annotation (e.g. `@EnableEntityDefinedRegions`)
|
||||
for convenience, since there is no convention or "opinion" provided by SBDG out-of-the-box.
|
||||
|
||||
In all remaining cases, it boils down to understanding how GemFire/Geode works under-the-hood. While we go to great
|
||||
lengths to shield users from as many details as possible, it is not feasible or practical to address all matters,
|
||||
e.g. cache creation and Security.
|
||||
|
||||
Hope this section provided some relief and clarity.
|
||||
Reference in New Issue
Block a user