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:

Required Security Properties in a Non-Manage Envionment
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 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:

Configuring Caches (Regions)
@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:

Defining Queries for CQ
@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:

Function Implementation
@Component
class GemFireFunctions {

  @GemfireFunction
  Object exampleFunction(Object arg) {
    ...
  }
}

And then define the execution:

Function 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:

Customer’s Repository
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.