Spring Session

John Blum

Table of Contents

1. Introduction
2. Samples and Guides (Start Here)
3. HttpSession Integration
3.1. Why Spring Session & HttpSession?
3.2. HttpSession with Apache Geode
3.2.1. Apache Geode Client-Server
Apache Geode Client-Server Java-based Configuration
Spring Java Configuration
Java Servlet Container Initialization
Apache Geode Client-Server XML-based Configuration
Spring XML Configuration
XML Servlet Container Initialization
3.2.2. Apache Geode Peer-To-Peer (P2P)
Apache Geode Peer-To-Peer (P2P) Java-based Configuration
Spring Java Configuration
Java Servlet Container Initialization
Apache Geode Peer-To-Peer (P2P) XML-based Configuration
Spring XML Configuration
XML Servlet Container Initialization
3.3. How HttpSession Integration Works
3.4. HttpSessionListener
3.5. Session
3.6. SessionRepository
3.7. FindByIndexNameSessionRepository
3.8. EnableSpringHttpSession
3.9. EnableGemFireHttpSession
3.10. GemFireOperationsSessionRepository
3.10.1. Using Indexes with Apache Geode
3.10.2. Using Indexes with Apache Geode & Spring Security
3.10.3. Using Custom Indexes with GemFire
4. Spring Session Community
4.1. Support
4.2. Source Code
4.3. Issue Tracking
4.4. Contributing
4.5. License
5. Minimum Requirements

Spring Session provides an API and implementations for managing a user’s session information.

1. Introduction

Spring Session provides an API and implementations for managing a user’s session information. It also provides transparent integration with:

  • HttpSession - allows replacing the javax.servlet.http.HttpSession in an application container (e.g. Tomcat) neutral way.

Additional features include:

  • Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.
  • Multiple Browser Sessions - Spring Session supports managing multiple user sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).
  • REST API - Spring Session allows providing the session ID in headers to work with REST APIs.
  • WebSocket - provides the ability to keep the javax.servlet.http.HttpSession alive when receiving WebSocket messages

2. Samples and Guides (Start Here)

If you are looking to get started with Spring Session right of way, the best place to start is with our Sample Applications.

Table 2.1. Sample Applications using Spring Boot

SourceDescriptionGuide

HttpSession with Spring Boot and Apache Geode

Demonstrates how to use Spring Session to manage the HttpSession with Apache Geode in a Spring Boot application using a Client/Server topology.

HttpSession with Spring Boot and Apache Geode Guide


Table 2.2. Sample Applications using Spring Java-based configuration

SourceDescriptionGuide

HttpSession with Apache Geode (Client/Server)

Demonstrates how to use Spring Session to manage the HttpSession with Apache Geode using a Client/Server topology.

HttpSession with Apache Geode (Client/Server) Guide

HttpSession with Apache Geode (P2P)

Demonstrates how to use Spring Session to manage the HttpSession with Apache Geode using a P2P topology.

HttpSession with Apache Geode (P2P) Guide


Table 2.3. Sample Applications using Spring XML-based configuration

SourceDescriptionGuide

HttpSession with Apache Geode (Client/Server)

Demonstrates how to use Spring Session to manage the HttpSession with Apache Geode using a Client/Server topology.

HttpSession with Apache Geode (Client/Server) Guide

HttpSession with Apache Geode (P2P)

Demonstrates how to use Spring Session to manage the HttpSession with Apache Geode using a P2P topology.

HttpSession with Apache Geode (P2P) Guide


3. HttpSession Integration

Spring Session provides transparent integration with HttpSession. This means that developers can switch the javax.servlet.http.HttpSession implementation out with an implementation that is backed by Spring Session.

3.1 Why Spring Session & HttpSession?

We already mentioned that Spring Session provides transparent integration with HttpSession, but what benefits do we get out of this?

  • Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.
  • Multiple Browser Sessions - Spring Session supports multiple user sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).
  • RESTful APIs - Spring Session allows providing the session ID in headers to work with REST APIs.
  • WebSocket - provides the ability to keep the javax.servlet.http.HttpSession alive when receiving WebSocket messages

3.2 HttpSession with Apache Geode

When Apache Geode is used with Spring Session, a web application’s javax.servlet.http.HttpSession can be replaced with a clustered implementation managed by Apache Geode and conveniently accessed using Spring Session’s API.

The two most common topologies to manage Spring Sessions using Apache Geode include:

Additionally, Apache Geode supports site-to-site replication using WAN technology. The ability to configure and use Apache Geode’s WAN support is independent of Spring Session, and beyond the scope of this document.

More details on configuring Apache Geode WAN functionality using Spring Data Geode can be found here.

3.2.1 Apache Geode Client-Server

The Client-Server topology will probably be the more common configuration choice among users when using Apache Geode as a provider in Spring Session since a Geode server will have significantly different and unique JVM heap requirements as compared to the application. Using a Client-Server topology enables an application to manage (e.g. replicate) application state independently from other application processes.

In a Client-Server topology, an application using Spring Session will open 1 or more connections to a remote cluster of Geode servers that will manage access to all HttpSession state.

You can configure a Client-Server topology with either:

Apache Geode Client-Server Java-based Configuration

This section describes how to configure Apache Geode’s Client-Server topology with Java-based configuration.

[Note]Note

The HttpSession with Apache Geode (Client-Server) provides a working sample demonstrating how to integrate Spring Session with Apache Geode to manage the HttpSession using Java configuration. You can read through the basic steps of integration below, but you are encouraged to follow along in the detailed `HttpSession` with Apache Geode (Client-Server) Guide when integrating with your own application.

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.

Client Configuration

Add the following Spring configuration:

@ClientCacheApplication(name = "SpringSessionDataGeodeClientJavaConfigSample", logLevel = "warning",
	pingInterval = 5000L, readTimeout = 15000, retryAttempts = 1, subscriptionEnabled = true) 1
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 30, poolName = "DEFAULT") 2
public class ClientConfig extends IntegrationTestConfig {

	// Required to resolve property placeholders in Spring @Value annotations.
	@Bean
	static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	@Bean
	ClientCacheConfigurer clientCacheServerPortConfigurer(
			@Value("${spring.session.data.geode.cache.server.port:40404}") int port) { 3

		return (beanName, clientCacheFactoryBean) ->
			clientCacheFactoryBean.setServers(Collections.singletonList(
				newConnectionEndpoint("localhost", port)));
	}
}

1

First, we declare our Web application to be a Geode cache client by annotating our ClientConfig class with @ClientCacheApplication. Additionally, we adjust a few basic, "DEFAULT" Pool settings.

2

@EnableGemFireHttpSession creates a Spring bean named springSessionRepositoryFilter that implements javax.servlet.Filter. The filter is what replaces the HttpSession with an implementation provided by Spring Session and backed by Apache Geode. This 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 will be sent from the cache client Web application to the server through Region data access operations. The client-side Region will use the "DEFAULT" Pool.

3

Then, we adjust the port used by the cache client Pool to connect to the CacheServer using a SDG ClientCacheConfigurer.

[Tip]Tip

In typical Geode production deployments, where the cluster includes potentially hundreds or thousands of Geode servers (data nodes), it is more common for clients to connect to 1 or more Geode Locators running in the cluster. A Locator passes meta-data to clients about the servers available in the cluster, the 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 operations. See more details about the Client/Server Deployment in the Apache Geode User Guide.

[Note]Note

For more information on configuring _Spring Data Geode, refer to the Reference Guide.

@EnableGemFireHttpSession enables a developer 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 a Geode ClientRegionShortcut (default is PROXY). This attribute is only used when configuring a client Region.
  • indexableSessionAttributes - Identifies the Session attributes by name that should be indexed for querying operations. Only Session attributes 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. The 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 using a Geode RegionShortcut (default is PARTITION). This attribute is only used when configuring server Regions, or when a P2P topology is employed.
[Note]Note

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 Sessions 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 cluster.

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 spin up an Apache Geode Server:

@CacheServerApplication(name = "SpringSessionSampleJavaConfigGemFireClientServer", logLevel = "warning") 1
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 30) 2
public class ServerConfig {

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		new AnnotationConfigApplicationContext(ServerConfig.class).registerShutdownHook();
	}

	// Required to resolve property placeholders in Spring @Value annotations.
	@Bean
	static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	@Bean
	CacheServerConfigurer cacheServerPortConfigurer(
			@Value("${spring.session.data.geode.cache.server.port:40404}") int port) { 3

		return (beanName, cacheServerFactoryBean) -> {
			cacheServerFactoryBean.setPort(port);
		};
	}
}

1

First, we use the new Spring Data Geode configuration annotation @CacheServerApplication to simplify the creation of a peer cache instance along with a CacheServer for cache clients to connect.

2

(Optional) Then, the ServerConfig class is annotated with @EnableGemFireHttpSession to create the necessary server-side Region (by default, "ClusteredSpringSessions") used to store the HttpSessions state. This step is optional since the Session Region could be created manually, perhaps using external means. Using @EnableGemFireHttpSession is convenient.

3

Finally, we adjust the port that the CacheServer will use to listen for cache clients by declaring a CacheServerConfigurer bean to modify the SDG CacheServerFactoryBean using property placeholders.

The sample makes use of Spring’s PropertySourcesPlaceholderConfigurer in order to externalize the sample application’s configuration using a properties file or with JVM System properties, which ever.

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 of these 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
	}
}

[Note]Note

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.

Apache Geode Client-Server XML-based Configuration

This section describes how to use Apache Geode’s Client-Server topology to back an HttpSession with XML-based configuration.

[Note]Note

The HttpSession with Apache Geode (Client-Server) using XML provides a working sample demonstrating how to integrate Spring Session with Apache Geode to manage the HttpSession using XML configuration. You can read through the basic steps of integration below, but you are encouraged to follow along in the detailed `HttpSession` with Apache Geode (Client-Server) using XML Guide when integrating with your own application.

Spring XML 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 javax.servlet.http.HttpSession with an implementation backed by Spring Session and Apache Geode.

Client Configuration

Add the following Spring configuration:

	<context:annotation-config/>

	<context:property-placeholder location="classpath:META-INF/spring/application.properties"/>

	<bean class="sample.ClientServerReadyBeanPostProcessor"/>

	1
	<util:properties id="gemfireProperties">
		<prop key="log-level">${spring.session.data.geode.log-level:warning}</prop>
	</util:properties>

	2
	<gfe:client-cache properties-ref="gemfireProperties" pool-name="gemfirePool"/>

	3
	<gfe:pool ping-interval="5000" read-timeout="15000" retry-attempts="1" subscription-enabled="true">
		<gfe:server host="${application.geode.client-server.host}"
                    port="${spring.session.data.geode.cache.server.port:${application.geode.client-server.port:40404}}"/>
	</gfe:pool>

	4
	<bean class="org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration"
		  p:maxInactiveIntervalInSeconds="30" p:poolName="DEFAULT"/>

1

(Optional) First, we can include a Properties bean to configure certain aspects of the Apache Geode ClientCache using GemFire Properties. In this case, we are just setting Apache Geode’s “log-level” from a application-specific System property, defaulting to “warning” if unspecified.

2

We must create an instance of an Apache Geode ClientCache initialized with our gemfireProperties.

3

Then we configure a Pool of client connections to talk to the Apache Geode Server in our Client/Server topology. In our configuration, we use sensible settings for timeouts, number of connections and so on. Also, our Pool has been configured to connect directly to the server.

4

Finally, a GemFireHttpSessionConfiguration bean is registered to enable Spring Session functionality.

[Tip]Tip

In typical Geode production deployments, where the cluster includes potentially hundreds or thousands of Geode servers (data nodes), it is more common for clients to connect to 1 or more Geode Locators running in the cluster. A Locator passes meta-data to clients about the servers available in the cluster, the 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 operations. See more details about the Client/Server Deployment in the Apache Geode User Guide.

[Note]Note

For more information on configuring _Spring Data Geode, refer to the Reference Guide.

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 XML configuration to spin up an Apache Geode Server:

	<context:annotation-config/>

	<context:property-placeholder location="classpath:META-INF/spring/application.properties"/>

	1
	<util:properties id="gemfireProperties">
		<prop key="name">SpringSessionSampleXmlGemFireClientServer</prop>
		<prop key="log-level">${spring.session.data.gemfire.log-level:warning}</prop>
<!--
		<prop key="jmx-manager">true</prop>
		<prop key="jmx-manager-start">true</prop>
-->
	</util:properties>

	2
	<gfe:cache properties-ref="gemfireProperties"/>

	3
	<gfe:cache-server auto-startup="true"
                      bind-address="${application.geode.client-server.host:localhost}"
                      host-name-for-clients="${application.geode.client-server.host:localhost}"
                      port="${spring.session.data.geode.cache.server.port:${application.geode.client-server.port:40404}}"/>

	4
	<bean class="org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration"
		  p:maxInactiveIntervalInSeconds="30"/>

1

(Optional) First, we can include a Properties bean to configure certain aspects of the Apache Geode peer Cache using GemFire Properties. In this case, we are just setting Apache Geode’s “log-level” from a application-specific System property, defaulting to “warning” if unspecified.

2

We must configure an Apache Geode peer Cache instance initialized with the Apache Geode properties.

3

Next, we define a CacheServer with sensible configuration for bind-address and port used by our cache client application to connect to the server to pass Session state.

4

Finally, we enable the same Spring Session functionality we declared in the client XML configuration by registering an instance of GemFireHttpSessionConfiguration, except we set the Session expiration timeout to 30 seconds. We explain what this means later.

The Apache Geode Server gets bootstrapped with the following:

@Configuration 1
@ImportResource("META-INF/spring/session-server.xml") 2
public class ServerConfig {

	public static void main(String[] args) {
		new AnnotationConfigApplicationContext(ServerConfig.class).registerShutdownHook();
	}
}
[Tip]Tip

Rather than defining a simple Java class with a main method, you might consider using Spring Boot instead.

1

The @Configuration annotation designates this Java class as a source of Spring configuration meta-data using 7.9. Annotation-based container configuration[Spring’s annotation configuration support].

2

Primarily, the configuration comes from the META-INF/spring/session-server.xml file.

XML Servlet Container Initialization

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

In order for our Filter to do its magic, we need to instruct Spring to load our session-client.xml configuration file.

We do this with the following configuration:

src/main/webapp/WEB-INF/web.xml. 

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/session-client.xml</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

The ContextLoaderListener reads the contextConfigLocation context parameter value and picks up our session-client.xml configuration file.

Finally, we need to ensure that our Servlet container (i.e. Tomcat) uses our springSessionRepositoryFilter for every request.

The following snippet performs this last step for us:

src/main/webapp/WEB-INF/web.xml. 

<filter>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>ERROR</dispatcher>
</filter-mapping>

The DelegatingFilterProxy will look up a bean by the name of springSessionRepositoryFilter and cast it to a Filter. For every HTTP request, the DelegatingFilterProxy is invoked, which delegates to the springSessionRepositoryFilter.

3.2.2 Apache Geode Peer-To-Peer (P2P)

Perhaps a less common approach is to configure the Spring Session application as a peer member in the Geode cluster using the Peer-To-Peer (P2P) topology. In this configuration, the Spring Session application would be an actual server (data node) in the Geode cluster, and not a cache client as before.

One advantage to this approach is the proximity of the application to the application’s state (i.e. its data). However, there are other effective means of accomplishing similar data dependent computations, such as using Geode’s Function Execution. Any of Geode’s other features can be used when Geode is serving as a provider in Spring Session.

P2P is very useful for testing purposes as well as for smaller, more focused and self-contained applications, such as those found in a microservices architecture, and will most certainly improve on your application’s perceived latency, throughput and consistency needs.

You can configure a Peer-To-Peer (P2P) topology with either:

Apache Geode Peer-To-Peer (P2P) Java-based Configuration

This section describes how to configure Apache Geode’s Peer-To-Peer (P2P) topology to manage an HttpSession using Java-based configuration.

[Note]Note

The HttpSession with Apache Geode (P2P) provides a working sample demonstrating how to integrate Spring Session with Apache Geode to manage the HttpSession using Java configuration. You can read through the basic steps of integration below, but you are encouraged to follow along in the detailed `HttpSession` with Apache Geode (P2P) Guide when integrating with your own application.

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 javax.servlet.http.HttpSession with an implementation backed by Spring Session and Apache Geode.

Add the following Spring configuration:

@PeerCacheApplication(name = "SpringSessionSampleJavaConfigGemFireP2p", logLevel = "warning") 1
@EnableGemFireHttpSession 2
@EnableManager(start = true) 3
public class Config {

}

1

First, we use the new Spring Data Geode configuration annotation @PeerCacheApplication to simplify the creation of a peer cache instance.

2

Then, the Config class is annotated with @EnableGemFireHttpSession to create the necessary server-side Region (by default, "ClusteredSpringSessions") used to store the HttpSessions state.

3

(Optionally) Finally, we annotated the Config class with @EnableManager to start an embedded Apache Geode Manager service to allow JMX clients (e.g. Apache Geode’s Gfsh shell tool) to connect and inspect the server.

[Note]Note

For more information on configuring _Spring Data Geode, refer to the Reference Guide.

@EnableGemFireHttpSession enables a developer 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 a Geode ClientRegionShortcut (default is PROXY). This attribute is only used when configuring a client Region.
  • indexableSessionAttributes - Identifies the Session attributes by name that should be indexed for querying operations. Only Session attributes 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. The 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 using a Geode RegionShortcut (default is PARTITION). This attribute is only used when configuring server Regions, or when a P2P topology is employed.

Java Servlet Container Initialization

Our <<[httpsession-spring-java-configuration-gemfire-p2p,Spring Java Configuration>> created a Spring bean named springSessionRepositoryFilter that implements javasx.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 our Config class. We also need to ensure our Servlet container (i.e. Tomcat) uses our springSessionRepositoryFilter on every HTTP request.

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

You can find an example below:

src/main/java/sample/Initializer.java. 

public class Initializer extends AbstractHttpSessionApplicationInitializer { 1

	public Initializer() {
		super(Config.class); 2
	}
}

[Note]Note

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 Config class.

Apache Geode Peer-To-Peer (P2P) XML-based Configuration

This section describes how to use Apache Geode’s Peer-To-Peer (P2P) topology to back an HttpSession using XML-based configuration.

[Note]Note

The HttpSession with Apache Geode (P2P) using XML provides a working sample demonstrating how to integrate Spring Session with Apache Geode to manage the HttpSession using XML configuration. You can read through the basic steps of integration below, but you are encouraged to follow along in the detailed `HttpSession` with Apache Geode (P2P) using XML Guide when integrating with your own application.

Spring XML 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 javax.servlet.http.HttpSession with an implementation backed by Spring Session and Apache Geode.

Add the following Spring configuration:

src/main/webapp/WEB-INF/spring/session.xml. 

<context:annotation-config/>

<context:property-placeholder/>

1
<util:properties id="gemfireProperties">
	<prop key="name">SpringSessionSampleXmlGemFireP2p</prop>
	<prop key="log-level">${spring.session.data.geode.log-level:warning}</prop>
	<prop key="jmx-manager">true</prop>
	<prop key="jmx-manager-start">true</prop>
</util:properties>

2
<gfe:cache properties-ref="gemfireProperties" use-bean-factory-locator="false"/>

3
<bean class="org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration"/>

1

(Optional) First, we can include a Properties bean to configure certain aspects of the Apache Geode peer Cache using GemFire Properties. In this case, we are just setting Apache Geode’s “log-level” from a application-specific System property, defaulting to “warning” if unspecified.

2

We must configure an Apache Geode peer Cache instance initialized with the Apache Geode properties.

3

Finally, we enable Spring Session functionality by registering an instance of GemFireHttpSessionConfiguration.

[Tip]Tip

Additionally, we have configured this data node (server) as a Apache Geode Manager as well using Geode-specific JMX properties that enable JMX client (e.g. Gfsh) to connect to this running server.

[Note]Note

For more information on configuring _Spring Data Geode, refer to the Reference Guide.

XML Servlet Container Initialization

The Spring XML 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 that is backed by Spring Session and Apache Geode.

In order for our Filter to do its magic, we need to instruct Spring to load our session.xml configuration file.

We do this with the following configuration:

src/main/webapp/WEB-INF/web.xml. 

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/spring/*.xml
	</param-value>
</context-param>
<listener>
	<listener-class>
		org.springframework.web.context.ContextLoaderListener
	</listener-class>
</listener>

The ContextLoaderListener reads the contextConfigLocation context parameter value and picks up our session.xml configuration file.

Finally, we need to ensure that our Servlet container (i.e. Tomcat) uses our springSessionRepositoryFilter for every HTTP request.

The following snippet performs this last step for us:

src/main/webapp/WEB-INF/web.xml. 

<filter>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>ERROR</dispatcher>
</filter-mapping>

The DelegatingFilterProxy will look up a bean by the name of springSessionRepositoryFilter and cast it to a Filter. For every HTTP request the DelegatingFilterProxy is invoked, delegating to the springSessionRepositoryFilter.

3.3 How HttpSession Integration Works

Fortunately both javax.servlet.http.HttpSession and javax.servlet.http.HttpServletRequest (the API for obtaining an HttpSession) are both interfaces. This means that we can provide our own implementations for each of these APIs.

[Note]Note

This section describes how Spring Session provides transparent integration with javax.servlet.http.HttpSession. The intent is so users understand what is happening under the hood. This functionality is already integrated and you do NOT need to implement this logic yourself.

First, we create a custom javax.servlet.http.HttpServletRequest that returns a custom implementation of javax.servlet.http.HttpSession. It looks something like the following:

public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {

	public SessionRepositoryRequestWrapper(HttpServletRequest original) {
		super(original);
	}

	public HttpSession getSession() {
		return getSession(true);
	}

	public HttpSession getSession(boolean createNew) {
		// create an HttpSession implementation from Spring Session
	}

	// ... other methods delegate to the original HttpServletRequest ...
}

Any method that returns an javax.servlet.http.HttpSession is overridden. All other methods are implemented by javax.servlet.http.HttpServletRequestWrapper and simply delegate to the original javax.servlet.http.HttpServletRequest implementation.

We replace the javax.servlet.http.HttpServletRequest implementation using a Servlet Filter called SessionRepositoryFilter. The pseudocode can be found below:

public class SessionRepositoryFilter implements Filter {

	public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {

		HttpServletRequest httpRequest = (HttpServletRequest) request;

		SessionRepositoryRequestWrapper customRequest = new SessionRepositoryRequestWrapper(httpRequest);

		chain.doFilter(customRequest, response, chain);
	}

	// ...
}

By passing in a custom javax.servlet.http.HttpServletRequest implementation into the FilterChain we ensure that anything invoked after our Filter uses the custom javax.servlet.http.HttpSession implementation.

This highlights why it is important that Spring Session’s SessionRepositoryFilter must be placed before anything that interacts with the javax.servlet.http.HttpSession.

3.4 HttpSessionListener

Spring Session supports HttpSessionListener by translating SessionDestroyedEvent and SessionCreatedEvent into HttpSessionEvent by declaring SessionEventHttpSessionListenerAdapter.

To use this support, you need to:

  • Ensure your SessionRepository implementation supports and is configured to fire SessionDestroyedEvent and SessionCreatedEvent.
  • Configure SessionEventHttpSessionListenerAdapter as a Spring bean.
  • Inject every HttpSessionListener into the SessionEventHttpSessionListenerAdapter

If you are using the configuration support documented in HttpSession with Apache Geode, then all you need to do is register every HttpSessionListener as a bean.

For example, assume you want to support Spring Security’s concurrency control and need to use HttpSessionEventPublisher you can simply add HttpSessionEventPublisher as a bean.

3.5 Session

A Session is a simplified Map of key/value pairs with support for expiration.

3.6 SessionRepository

A SessionRepository is in charge of creating, retrieving, and persisting Session instances.

If possible, developers should not interact directly with a SessionRepository or a Session. Instead, developers should prefer to interact with SessionRepository and Session indirectly through the javax.servlet.http.HttpSession and WebSocket integration.

3.7 FindByIndexNameSessionRepository

Spring Session’s most basic API for using a Session is the SessionRepository. The API is intentionally very simple so that it is easy to provide additional implementations with basic functionality.

Some SessionRepository implementations may choose to implement FindByIndexNameSessionRepository also. For example, Spring Session’s Apache Geode support implements FindByIndexNameSessionRepository.

The FindByIndexNameSessionRepository provides a single method to look up all the Sessions for a particular user. This is done by ensuring that the session attribute with the name FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME is populated with the username. It is the responsibility of the developer to ensure the attribute is populated since Spring Session is not aware of the authentication mechanism being used.

[Note]Note

Some implementations of FindByIndexNameSessionRepository will provide hooks to automatically index other session attributes. For example, many implementations will automatically ensure the current Spring Security user name is indexed with the index name FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME.

3.8 EnableSpringHttpSession

The @EnableSpringHttpSession annotation can be added to any @Configuration class to expose the SessionRepositoryFilter as a bean in the Spring application context named "springSessionRepositoryFilter".

In order to leverage the annotation, a single SessionRepository bean must be provided.

3.9 EnableGemFireHttpSession

The @EnableGemFireHttpSession annotation can be added to any @Configuration class in place of the @EnableSpringHttpSession annotation to expose the SessionRepositoryFilter as a bean in the Spring application context named "springSessionRepositoryFilter" and to position Apache Geode as a provider to manage the javax.servlet.http.HttpSession.

When using the @EnableGemFireHttpSession annotation, additional configuration is imported out-of-the-box that also provides a Geode specific implementation of the SessionRepository interface, the GemFireOperationsSessionRepository.

3.10 GemFireOperationsSessionRepository

GemFireOperationsSessionRepository is a SessionRepository implementation that is implemented using Spring Session Data Geode’s GemFireOperationsSessionRepository.

In a web environment, this repository is used in conjunction with the SessionRepositoryFilter.

This implementation supports SessionCreatedEvents, SessionDeletedEvents and SessionDestroyedEvents through SessionEventHttpSessionListenerAdapter.

3.10.1 Using Indexes with Apache Geode

While best practices concerning the proper definition of Indexes that positively impact Geode’s performance is beyond the scope of this document, it is important to realize that Spring Session Data Geode creates and uses Indexes to query and find Sessions efficiently.

Out-of-the-box, Spring Session Data Geode creates 1 Hash-typed Index on the principal name. There are two different built-in strategies for finding the principal name. The first strategy is that the value of the Session attribute with the name FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME will be Indexed to the same index name.

For example:

String indexName = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;

session.setAttribute(indexName, username);
Map<String, Session> idToSessions =
	this.sessionRepository.findByIndexNameAndIndexValue(indexName, username);

3.10.2 Using Indexes with Apache Geode & Spring Security

Alternatively, Spring Session Data Geode will map Spring Security’s current Authentication#getName() to the Index FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME.

For example, if you are using Spring Security you can find the current user’s sessions using:

SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
String indexName = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;

Map<String, Session> idToSessions =
	this.sessionRepository.findByIndexNameAndIndexValue(indexName, authentication.getName());

3.10.3 Using Custom Indexes with GemFire

This enables developers using the GemFireOperationsSessionRepository programmatically to query and find all Sessions with a given principal name efficiently.

Additionally, Spring Session Data Geode will create a Range-based Index on the implementing Session’s Map-type attributes property (i.e. on any arbitrary Session attribute) when a developer identifies 1 or more named Session attributes that should be indexed by Geode.

Sessions attributes to index can be specified with the indexableSessionAttributes attribute on the @EnableGemFireHttpSession annotation. A developer adds this annotation to their Spring application @Configuration class when s/he wishes to enable Spring Session’s support for HttpSession backed by Apache Geode.

String indexName = "name1";

session.setAttribute(indexName, indexValue);
Map<String, Session> idToSessions =
	this.sessionRepository.findByIndexNameAndIndexValue(indexName, indexValue);
[Note]Note

Only Session attribute names identified in the @EnableGemFireHttpSession annotation’s indexableSessionAttributes attribute will have an Index defined. All other Session attributes will not be indexed.

However, there is one caveat. Any values stored in indexable Session attributes must implement the java.lang.Comparable<T> interface. If those object values do not implement Comparable, then GemFire will throw an error on startup when the Index is defined for Regions with persistent Session data, or when an attempt is made at runtime to assign the indexable Session attribute a value that is not Comparable and the Session is saved to GemFire.

[Note]Note

Any Session attribute that is not indexed may store non-Comparable values.

To learn more about GemFire’s Range-based Indexes, see Creating Indexes on Map Fields.

To learn more about GemFire Indexing in general, see Working with Indexes.

4. Spring Session Community

We are glad to consider you a part of our community. Please find additional information below.

4.1 Support

You can get help by asking questions on StackOverflow with the tag spring-session. Similarly we encourage helping others by answering questions on StackOverflow.

4.2 Source Code

The source code can be found on GitHub at https://github.com/spring-projects/spring-session-data-geode

4.3 Issue Tracking

We track issues in GitHub Issues at https://github.com/spring-projects/spring-session-data-geode/issues

4.4 Contributing

We appreciate Pull Requests.

4.5 License

Spring Session Data Geode and Spring Session Data GemFire are Open Source Software released under the Apache 2.0 license.

5. Minimum Requirements

The minimum requirements for Spring Session are:

  • Java 8+
  • If you are running in a Servlet container (not required), Servlet 2.5+
  • If you are using other Spring libraries (not required), the minimum required version is Spring Framework 5.0.0.RC2.
  • @EnableGemFireHttpSession requires Spring Data Geode 2.0.0.RC2 and Spring Data GemFire 2.0.0.RC2.
  • @EnableGemFireHttpSession requires Apache Geode 1.2.0 or Pivotal GemFire 9.1.0.
[Note]Note

At its core Spring Session only has a required dependency on spring-jcl.