This guide describes how to configure Spring Session to transparently leverage Apache Geode to manage a Web application’s javax.servlet.http.HttpSession using Java Configuration.

1. Updating Dependencies

Before using Spring Session, you must ensure that the required dependencies are included. If you are using Maven, include the following dependencies in your pom.xml:

pom.xml
<dependencies>
	<!-- ... -->

	<dependency>
		<groupId>org.springframework.session</groupId>
		<artifactId>spring-session-data-geode</artifactId>
		<version>2.2.2.RELEASE</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-web</artifactId>
		<version>5.2.3.RELEASE</version>
	</dependency>
</dependencies>

2. Spring Java Configuration

After adding the required dependencies and repository declarations, we can create the Spring configuration. The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession with an implementation backed by Spring Session and Apache Geode.

2.1. Client Configuration

Add the following Spring configuration:

@ClientCacheApplication(name = "SpringSessionDataGeodeJavaConfigSampleClient", logLevel = "error",
	readTimeout = 15000, retryAttempts = 1, subscriptionEnabled = true) (1)
@EnableGemFireHttpSession(poolName = "DEFAULT") (2)
public class ClientConfig extends ClientServerIntegrationTestsSupport {

	@Bean
	ClientCacheConfigurer gemfireServerReadyConfigurer( (3)
			@Value("${spring.data.gemfire.cache.server.port:40404}") int cacheServerPort) {

		return (beanName, clientCacheFactoryBean) -> waitForServerToStart("localhost", cacheServerPort);
	}
}
1 First, we declare our Web application to be an Apache Geode cache client by annotating our ClientConfig class with @ClientCacheApplication. Additionally, we adjust a few basic, "DEFAULT" Pool settings (e.g. readTimeout).
2 @EnableGemFireHttpSession creates a Spring bean named springSessionRepositoryFilter that implements javax.servlet.Filter. The filter replaces the HttpSession with an implementation provided by Spring Session and backed by Apache Geode. Additionally, the configuration will also create the necessary client-side Region (by default, "ClusteredSpringSessions`, which is a PROXY Region) corresponding to the same server-side Region by name. All session state is sent from the client to the server through Region data access operations. The client-side Region use the "DEFAULT" Pool.
3 Then, we wait to ensure the Apache Geode Server is up and running before we proceed. This is only really useful for automated (integration) testing purposes.
In typical Apache Geode production deployments, where the cluster includes potentially hundreds or thousands of servers (a.k.a. data nodes), it is more common for clients to connect to 1 or more Apache Geode Locators running in the same cluster. A Locator passes meta-data to clients about the servers available in the cluster, the individual server load and which servers have the client’s data of interest, which is particularly important for direct, single-hop data access and latency-sensitive applications. See more details about the {data-store-docs}/topologies_and_comm/cs_configuration/standard_client_server_deployment.html[Client/Server Deployment] in the Apache Geode User Guide.
For more information on configuring Spring Data Geode, refer to the {sdg-docs}[Reference Guide].

The @EnableGemFireHttpSession annotation enables developers to configure certain aspects of both Spring Session and Apache Geode out-of-the-box using the following attributes:

  • clientRegionShortcut - specifies Apache Geode {data-store-docs}/developing/region_options/region_types.html[data management policy] on the client with the {data-store-javadoc}/org/apache/geode/cache/client/ClientRegionShortcut.html[ClientRegionShortcut] (default is PROXY). This attribute is only used when configuring the client Region.

  • indexableSessionAttributes - Identifies the Session attributes by name that should be indexed for querying purposes. Only Session attributes explicitly identified by name will be indexed.

  • maxInactiveIntervalInSeconds - controls HttpSession idle-timeout expiration (defaults to 30 minutes).

  • poolName - name of the dedicated Apache Geode Pool used to connect a client to the cluster of servers. This attribute is only used when the application is a cache client. Defaults to gemfirePool.

  • regionName - specifies the name of the Apache Geode Region used to store and manage HttpSession state (default is "ClusteredSpringSessions").

  • serverRegionShortcut - specifies Apache Geode {data-store-docs}/developing/region_options/region_types.html[data management policy] on the server with the {data-store-javadoc}/org/apache/geode/cache/RegionShortcut.html[RegionShortcut] (default is PARTITION). This attribute is only used when configuring server Regions, or when a P2P topology is employed.

It is important to remember that the Apache Geode client Region name must match a server Region by the same name if the client Region is a PROXY or CACHING_PROXY. Client and server Region names are not required to match if the client Region used to store session state is LOCAL. However, keep in mind that Session state will not be propagated to the server and you lose all the benefits of using Apache Geode to store and manage distributed, replicated session state information on the servers in a distributed, replicated manner.

2.2. Server Configuration

So far, we only covered one side of the equation. We also need an Apache Geode Server for our cache client to talk to and send session state to the server to manage.

In this sample, we will use the following Java configuration to configure and run an Apache Geode Server:

@CacheServerApplication(name = "SpringSessionDataGeodeJavaConfigSampleServer", logLevel = "error") (1)
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 30) (2)
public class GemFireServer {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		new AnnotationConfigApplicationContext(GemFireServer.class).registerShutdownHook();
	}
}
1 First, we use the @CacheServerApplication annotation to simplify the creation of a peer cache instance containing with a CacheServer for cache clients to connect.
2 (Optional) Then, the GemFireServer class is annotated with @EnableGemFireHttpSession to create the necessary server-side Region (by default, "ClusteredSpringSessions") used to store HttpSession state. This step is optional since the Session Region could be created manually, perhaps using external means. Using @EnableGemFireHttpSession is convenient and quick.

3. Java Servlet Container Initialization

Our Spring Java Configuration created a Spring bean named springSessionRepositoryFilter that implements javax.servlet.Filter. The springSessionRepositoryFilter bean is responsible for replacing the javax.servlet.http.HttpSession with a custom implementation backed by Spring Session and Apache Geode.

In order for our Filter to do its magic, Spring needs to load the ClientConfig class. We also need to ensure our Servlet container (i.e. Tomcat) uses our springSessionRepositoryFilter for every request.

Fortunately, Spring Session provides a utility class named AbstractHttpSessionApplicationInitializer to make both steps extremely easy.

You can find an example below:

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)

	public Initializer() {
		super(ClientConfig.class); (2)
	}
}
The name of our class (Initializer) does not matter. What is important is that we extend AbstractHttpSessionApplicationInitializer.
1 The first step is to extend AbstractHttpSessionApplicationInitializer. This ensures that a Spring bean named springSessionRepositoryFilter is registered with our Servlet container and used on every HTTP request.
2 AbstractHttpSessionApplicationInitializer also provides a mechanism to easily allow Spring to load our ClientConfig.

4. HttpSession managed by a Java configured, Apache Geode Client/Server Sample Application

4.1. Running the Apache Geode Sample Application

You can run the sample by obtaining the source code and invoking the following commands.

First, you need to run the server using:

$ ./gradlew :spring-session-sample-javaconfig-gemfire-clientserver:run

Then, in a separate terminal, run the client using:

$ ./gradlew :spring-session-sample-javaconfig-gemfire-clientserver:tomcatRun

You should now be able to access the application at http://localhost:8080/.

In this sample, the web application is the Apache Geode cache client and the server is standalone, separate JVM process.

4.2. Exploring the httpsession-gemfire-clientserver Sample Application

Try using the application. Fill out the form with the following information:

  • Attribute Name: username

  • Attribute Value: john

Now click the Set Attribute button. You should now see the attribute name and value displayed in the table.

4.3. How does it work?

We interact with the standard HttpSession in the SessionServlet shown below:

src/main/java/sample/SessionServlet.java
@WebServlet("/session")
public class SessionServlet extends HttpServlet {

	private static final long serialVersionUID = 2878267318695777395L;

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String attributeName = request.getParameter("attributeName");
		String attributeValue = request.getParameter("attributeValue");

		request.getSession().setAttribute(attributeName, attributeValue);
		response.sendRedirect(request.getContextPath() + "/");
	}
}

Instead of using Tomcat’s HttpSession, we are actually persisting the Session in Apache Geode.

Spring Session creates a cookie named SESSION in your browser that contains the id of your Session. Go ahead and view the cookies (click for help with Chrome or Firefox).