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.
The completed guide can be found in the HttpSession managed by a Java configured, Apache Geode Client/Server Sample Application. |
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
:
<dependencies>
<!-- ... -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-geode</artifactId>
<version>2.7.2</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.31</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 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 isPROXY
). This attribute is only used when configuring the clientRegion
. -
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 GeodePool
used to connect a client to the cluster of servers. This attribute is only used when the application is a cache client. Defaults togemfirePool
. -
regionName
- specifies the name of the Apache GeodeRegion
used to store and manageHttpSession
state (default is "ClusteredSpringSessions"). -
serverRegionShortcut
- specifies Apache Geode data management policy on the server with the RegionShortcut (default isPARTITION
). This attribute is only used when configuring serverRegions
, 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 {
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:
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:
@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.