This guide describes how to build a Spring Boot application configured with Spring Session to transparently leverage Apache Geode to manage a web application’s javax.servlet.http.HttpSession.

In this sample, Apache Geode’s client/server topology is employed using a pair of Spring Boot applications, one to configure and run a Apache Geode Server and another to configure and run the cache client, Spring MVC-based web application making use of the HttpSession.

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.3.5.RELEASE</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

2. Spring Boot Configuration

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

2.1. Spring Boot, Apache Geode Cache Server

We start with a Spring Boot application to configure and bootstrap the Apache Geode Server:

@SpringBootApplication (1)
@CacheServerApplication(name = "SpringSessionDataGeodeBootSampleServer", logLevel = "error") (2)
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 20) (3)
public class GemFireServer {

	public static void main(String[] args) {

		new SpringApplicationBuilder(GemFireServer.class)
			.web(WebApplicationType.NONE)
			.build()
			.run(args);
	}
}
1 First, we annotate the Apache Geode Server configuration class (GemFireServer) with @SpringBootApplication to indicate that this is a Spring Boot application leveraging all of Spring Boot’s features (e.g. auto-configuration).
2 Next, we use the Spring Data for Apache Geode configuration annotation @CacheServerApplication to simplify the creation of a peer cache instance containing a CacheServer for cache clients to connect.
3 (Optional) Then, the @EnableGemFireHttpSession annotation is used to create the necessary server-side Region (by default, "ClusteredSpringSessions") to store the HttpSessions state. This step is optional since the Session Region could be created manually, perhaps even using external means. Using @EnableGemFireHttpSession is convenient and quick.

2.2. Spring Boot, Apache Geode Cache Client Web application

Now, we create a Spring Boot Web application to expose our Web service with Spring Web MVC, running as an Apache Geode cache client connected to our Spring Boot, Apache Geode Server. The Web application will use Spring Session backed by Apache Geode to manage HttpSession state in a clustered (distributed) and replicated manner.

@SpringBootApplication (1)
@Controller (2)
public class Application {

	static final String INDEX_TEMPLATE_VIEW_NAME = "index";
	static final String PING_RESPONSE = "PONG";
	static final String REQUEST_COUNT_ATTRIBUTE_NAME = "requestCount";

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@ClientCacheApplication(name = "SpringSessionDataGeodeBootSampleClient", logLevel = "error",
		readTimeout = 15000, retryAttempts = 1, subscriptionEnabled = true)  (3)
	@EnableGemFireHttpSession(poolName = "DEFAULT") (4)
	static class ClientCacheConfiguration extends ClientServerIntegrationTestsSupport {

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

			return (beanName, clientCacheFactoryBean) -> waitForServerToStart("localhost", cacheServerPort);
		}
	}

	@Configuration
	static class SpringWebMvcConfiguration {  (6)

		@Bean
		public WebMvcConfigurer webMvcConfig() {

			return new WebMvcConfigurer() {

				@Override
				public void addViewControllers(ViewControllerRegistry registry) {
					registry.addViewController("/").setViewName(INDEX_TEMPLATE_VIEW_NAME);
				}
			};
		}
	}

	@ExceptionHandler
	@ResponseBody
	public String errorHandler(Throwable error) {
		StringWriter writer = new StringWriter();
		error.printStackTrace(new PrintWriter(writer));
		return writer.toString();
	}

	@RequestMapping(method = RequestMethod.GET, path = "/ping")
	@ResponseBody
	public String ping() {
		return PING_RESPONSE;
	}

	@RequestMapping(method = RequestMethod.POST, path = "/session")
	public String session(HttpSession session, ModelMap modelMap,
			@RequestParam(name = "attributeName", required = false) String name,
			@RequestParam(name = "attributeValue", required = false) String value) { (7)

		modelMap.addAttribute("sessionAttributes",
			attributes(setAttribute(updateRequestCount(session), name, value)));

		return INDEX_TEMPLATE_VIEW_NAME;
	}
1 Again, we declare our Web application to be a Spring Boot application by annotating our application class with @SpringBootApplication.
2 @Controller is a Spring Web MVC annotation enabling our MVC handler mapping methods (i.e. methods annotated with @RequestMapping) to process HTTP requests (e.g. <7>)
3 We also declare our Web application to be an Apache Geode cache client by annotating our application class with @ClientCacheApplication. Additionally, we adjust a few basic, "DEFAULT" Pool settings (e.g. readTimeout).
4 Next, we declare that the Web application will use Spring Session backed by Apache Geode by annotating the ClientCacheConfiguration class with @EnableGemFireHttpSession. This will create the necessary client-side Region (by default, "ClusteredSpringSessions` as a PROXY Region) corresponding to the same server-side Region by name. All HttpSession state will be sent from the cache client Web application to the server through Region data access operations. The client-side Region uses the "DEFAULT" Pool.
5 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.
6 We adjust the Spring Web MVC configuration to set the home page, and…​
7 Finally, we declare the /sessions HTTP request handler method to set an HTTP Session attribute and increment a count for the number of HTTP requests.

There are many other useful utility methods, so please refer to the actual source code for full details.

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 Client/Server Deployment in the Apache Geode User Guide.
For more information on configuring Spring Data Geode, refer to the 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 management policy on the client with the 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 management policy on the server with the 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.

3. Spring Boot Sample Web Application with an Apache Geode managed HttpSession

3.1. Running the Boot Sample Application

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

First, you must run the server:

$ ./gradlew :spring-session-sample-boot-gemfire:run

Then, in a separate terminal, run the client:

$ ./gradlew :spring-session-sample-boot-gemfire:bootRun

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

In this sample, the Web application is the Spring Boot, Apache Geode cache client and the server is standalone, separate (JVM) process.

3.2. Exploring the Boot Sample Application

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

  • Attribute Name: username

  • Attribute Value: test

Now click the Set Attribute button. You should now see the attribute name and value displayed in the table along with an additional attribute (requestCount) indicating the number of Session interactions (via HTTP requests).

3.3. How does it work?

We interact with the standard javax.servlet.http.HttpSession in the the Spring Web MVC service endpoint, shown here for convenience:

src/main/java/sample/client/Application.java
@Controller
class Controller {

  @RequestMapping(method = RequestMethod.POST, path = "/session")
  public String session(HttpSession session, ModelMap modelMap,
		@RequestParam(name = "attributeName", required = false) String name,
		@RequestParam(name = "attributeValue", required = false) String value) {

    modelMap.addAttribute("sessionAttributes",
        attributes(setAttribute(updateRequestCount(session), name, value)));

    return INDEX_TEMPLATE_VIEW_NAME;
  }
}

Instead of using the embedded HTTP server’s HttpSession, we are actually persisting the Session state 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).