From 7539d9c82434d6455faab1f5f21a4da90c9e0918 Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 18 Apr 2019 13:00:07 -0700 Subject: [PATCH] Add section detailing the differences between Auto-configuration and Annotation-based configuration. Resolves gh-20. --- .../src/docs/asciidoc/appendix.adoc | 3 + .../asciidoc/configuration-annotations.adoc | 387 ++++++++++++++++++ 2 files changed, 390 insertions(+) create mode 100644 spring-geode-docs/src/docs/asciidoc/configuration-annotations.adoc diff --git a/spring-geode-docs/src/docs/asciidoc/appendix.adoc b/spring-geode-docs/src/docs/asciidoc/appendix.adoc index 43a009b6..14e1a977 100644 --- a/spring-geode-docs/src/docs/asciidoc/appendix.adoc +++ b/spring-geode-docs/src/docs/asciidoc/appendix.adoc @@ -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] diff --git a/spring-geode-docs/src/docs/asciidoc/configuration-annotations.adoc b/spring-geode-docs/src/docs/asciidoc/configuration-annotations.adoc new file mode 100644 index 00000000..572c108d --- /dev/null +++ b/spring-geode-docs/src/docs/asciidoc/configuration-annotations.adoc @@ -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 +<>, specified in Spring Boot `application.properties` (the "convention"), +or by using a {spring-data-gemfire-docs-html}/#bootstrap-annotation-config-configurers[Configurer]. + +See the <> 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 <> 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 <> 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 <> 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 <> +(search for "PDX") in Spring Boot `application.properties`. + +See the <> 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 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 <> 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.