1. 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.
Readers should refer to the complimentary sample, Spring Boot Auto-configuration for Apache Geode & Pivotal GemFire, which showcases the auto-configuration provided by Spring Boot for Apache Geode/Pivotal GemFire in action.
1.1. 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].
1.2. Conventions
Currently, SBDG provides auto-configuration for the following features:
-
ClientCache
-
Caching with Spring’s Cache Abstraction
-
Continuous Query
-
Function Execution & Implementation
-
Logging
-
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
-
@EnableLogging
-
@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.
1.3. Overriding
In this section, we cover a few examples to make the behavior when overriding more apparent.
1.3.1. 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:
@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
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 Reference Guide for more details.
1.3.2. 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:
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 due to the way Security (Auth) and SSL meta-data must be supplied to GemFire/Geode.
See the Reference Guide for more details.
1.4. 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.
1.4.1. 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
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:
@SpringBootApplication
@EnableCachingDefinedRegions
class Application { ... }
@EnableCachingDefinedRegions
is optional, provided for convenience, and complimentary to caching when used
rather than necessary.
See the Reference Guide for more details.
1.4.2. 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:
@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 Reference Guide for more details.
1.4.3. 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:
@Component
class GemFireFunctions {
@GemfireFunction
Object exampleFunction(Object arg) {
...
}
}
And then define the execution:
@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.
1.4.4. 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 Properties
(search for "PDX") in Spring Boot application.properties
.
See the Reference Guide for more details.
1.4.5. 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:
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 Reference Guide for more details.
1.5. 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
-
@EnableClusterDefinedRegions
-
@EnableCompression
-
@EnableDiskStore(s)
-
@EnableEntityDefinedRegions
-
@EnableEviction
-
@EnableExpiration
-
@EnableGatewayReceiver
-
@EnableGatewaySender(s)
-
@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.
1.6. 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.