[[gemfire-bootstrap]]
= Bootstrapping a Spring ApplicationContext in Apache Geode

== Introduction

Normally, a _Spring_-based application will <<bootstrap,bootstrap Apache Geode>> using _Spring Data Geode's.
Just by specifying a `<gfe:cache/>` element using the _Spring Data Geode_ XML namespace, a single, embedded Geode
peer `Cache` instance is created and initialized with default settings in the same JVM process as your application.

However, it is sometimes necessary, perhaps a requirement imposed by your IT organization, that Geode be fully managed
and operated using the provided Apache Geode tool suite, such as with
http://geode.apache.org/docs/guide/11/tools_modules/gfsh/chapter_overview.html[Gfsh].  By using _Gfsh_,
Geode will bootstrap your _Spring_ application context rather than the other way around.  Instead of
an application server, or a Java main class using _Spring Boot_, whatever, Geode does the bootstrapping and will
host your application.

Keep in mind, however, that Geode is not an application server.  In addition, there are limitations to using
this approach where Geode cache configuration is concerned.

[[gemfire-bootstrap-gfsh]]
== Using Apache Geode to Bootstrap a Spring Context Started with Gfsh

In order to bootstrap a _Spring_ application context in Geode when starting a Geode Server process using _Gfsh_,
a user must make use of Geode's
http://geode.apache.org/docs/guide/11/basic_config/the_cache/setting_cache_initializer.html[Initalizer] functionality.
An Initializer block can declare a callback application that is launched after the cache is initialized by Geode.

An Initializer is declared within an
http://geode.apache.org/docs/guide/11/reference/topics/cache_xml.html#initializer[initializer] element
using a minimal snippet of Geode's native `cache.xml`.  The `cache.xml` file is required in order to bootstrap
the _Spring_ application context, much like a minimal snippet of _Spring_ XML config is needed to bootstrap
a _Spring_ application context configured with component scanning (e.g. `<context:component-scan base-packages="..."/>`)

Fortunately, such an Initializer is already conveniently provided by the framework, the
http://docs.spring.io/spring-data-gemfire/docs/current/api/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.html[SpringContextBootstrappingInitializer].
A typical, yet very minimal configuration for this class inside Geodes's `cache.xml` file will look like this:

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="contextConfigLocations">
      <string>classpath:application-context.xml</string>
    </parameter>
  </initializer>

</cache>
----

The `SpringContextBootstrappingInitializer` class follows similar conventions as _Spring's_ `ContextLoaderListener`
class used to bootstrap a _Spring_ application context inside a Web Application, where application context
configuration files are specified with the `contextConfigLocations` Servlet Context Parameter.

In addition, the `SpringContextBootstrappingInitializer` class can also be used with a `basePackages` parameter
to specify a comma-separated list of base packages containing appropriately annotated application components
that the _Spring_ container will search in order to find and create _Spring_ beans and other application components
on the classpath:

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="basePackages">
      <string>org.mycompany.myapp.services,org.mycompany.myapp.dao,...</string>
    </parameter>
  </initializer>

</cache>
----

Then, with a properly configured and constructed `CLASSPATH` along with `cache.xml` file shown above, specified as
a command-line option when starting a Geode Server in _Gfsh_, the command-line would be:

[source]
----
gfsh>start server --name=Server1 --log-level=config ...
    --classpath="/path/to/application/classes.jar:/path/to/spring-data-geode-<major>.<minor>.<maint>.RELEASE.jar"
    --cache-xml-file="/path/to/geode/cache.xml"
----

The `application-context.xml` can be any valid _Spring_ context configuration meta-data including all the SDG namespace
elements.  The only limitation with this approach is that a GemFire cache cannot be configured using
the _Spring Data Geode_ namespace.  In other words, none of the `<gfe:cache/>` element attributes,
such as `cache-xml-location`, `properties-ref`, `critical-heap-percentage`, `pdx-serializer-ref`, `lock-lease`, etc,
can be specified.  If used, these attributes will be ignored.

The reason for this is that Geode itself has already created an initialized the cache before the Initializer
gets invoked.  As such, the cache will already exist and since it is a "Singleton", it cannot be re-initialized
or have any of it's configuration augmented.

[[gemfire-bootstrap-lazywiring]]
== Lazy-Wiring GemFire Components

_Spring Data Geode_ already provides existing support for wiring Geode components, such as `CacheListeners`,
`CacheLoaders`, `CacheWriters` and so on, that are declared and created by Geode in `cache.xml` using
SDG's `WiringDeclarableSupport` class as described in <<apis:declarable:autowiring>>.  However, this only works
when _Spring_ is the one doing the bootstrapping (i.e. bootstrapping Geode).

When your _Spring_ application context is bootstrapped by Geode, then these Geode application components go unnoticed
since the _Spring_ application context does not even exist yet!  The _Spring_ application context will not get created
until Geode calls the Initializer block, which only occurs after all the other Geode components and configuration
have already been created and initialized.

So, in order to solve this problem, a new `LazyWiringDeclarableSupport` class was introduced that is, in a sense,
_Spring_ application context aware.  The intention of this abstract base class is that any implementing class
will register itself to be configured by the _Spring_ container that will eventually be created by Geode
once the Initializer is called.  In essence, this give your Geode defined application components a chance
to be configured and auto-wired with _Spring_ beans defined in the _Spring_ application context.

In order for your Geode application components to be auto-wired by the _Spring_ container, create an application class
that extends the `LazyWiringDeclarableSupport` and annotate any class member that needs to be provided as
a _Spring_ bean dependency, similar to:

[source,java]
----
public class UserDataSourceCacheLoader extends LazyWiringDeclarableSupport
    implements CacheLoader<String, User> {

  @Autowired
  private DataSource userDataSource;

  ...
}
----

As implied in the `CacheLoader` example above, you might necessarily (although, rarely) have defined both
a Region and `CacheListener` component in Geode `cache.xml`.  The `CacheLoader` may need access to an application DAO,
or perhaps a _Spring_ application context defined JDBC `DataSource` for loading `Users` into a Geode `REPLICATE` Region
on start.

CAUTION: Be careful when mixing the different life-cycles of Apache Geode and the _Spring_ Container together
in this manner as not all use cases and scenarios are supported. The Geode `cache.xml` configuration would be
similar to the following (which comes from SDG's test suite):

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://geode.apache.org/schema/cache"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0">

  <region name="Users" refid="REPLICATE">
    <region-attributes initial-capacity="101" load-factor="0.85">
      <key-constraint>java.lang.String</key-constraint>
      <value-constraint>org.springframework.data.gemfire.repository.sample.User</value-constraint>
      <cache-loader>
        <class-name>
          org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest$UserDataStoreCacheLoader
        </class-name>
      </cache-loader>
    </region-attributes>
  </region>

  <initializer>
    <class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
    <parameter name="basePackages">
      <string>org.springframework.data.gemfire.support.sample</string>
    </parameter>
  </initializer>

</cache>
----
