Home  >  Spring Session

Spring Session + Redis + Servlet Integration Example

By Arvind Rai, February 01, 2017
This page will walk through Spring session, Redis and Servlet integration example. By default a java web application uses servlet container to save session values. Spring session can externalize the persistence of session attributes values. We can use external source to save and fetch session ids. Here in our example we are using Redis. Session id will be stored as keys in Redis. Spring session replaces the HttpSession implementation by a custom implementation. To perform this task spring session creates a SessionRepositoryFilter bean named as springSessionRepositoryFilter. Spring Session with Redis works as follows.

1. Spring session exposes a SessionRepositoryFilter bean named as springSessionRepositoryFilter.
2. The bean springSessionRepositoryFilter is responsible to replace Servlet container HttpSession implementation by custom implementation such as Redis.
3. To use HttpSession backed by Redis using JavaConfig, Spring session provides @EnableRedisHttpSession annotation that will be annotated at java configuration class. @EnableRedisHttpSession exposes SessionRepositoryFilter bean named as springSessionRepositoryFilter .
4. To use HttpSession backed by Redis using XML configuration, Spring session provides RedisHttpSessionConfiguration class. We need to create a bean of this class in our spring application context XML file. RedisHttpSessionConfiguration exposes SessionRepositoryFilter bean named as springSessionRepositoryFilter .
5.To get connection with Redis, we need to create a bean of RedisConnectionFactory implementation. If we are using Lettuce then create the bean of LettuceConnectionFactory class in both cases JavaConfig as well as XML configuration.
6.When we run java servlet application and save values in session then it will not be saved in Tomcat Servlet container. Now the session values will be saved in Redis. Spring session creates a cookie with name SESSION instead of JSESSIONID in the browser.

Here we will provide complete example of spring session with servlet using Redis. We will use JavaConfig as well as XML configuration in our demo.

Software Used

Find the software used in our demo.
1. Java 8
2. Redis 2.8.17
3. Spring 4
4. Tomcat 8.0.12
5. Eclipse Mars

Redis Installation

To work with Spring Session using Redis, we need to install Redis in our system. Find the below steps to install Redis.
1. Go to the link and download the Redis. If operating system is Windows then visit the link. Minimum required version of Redis for Spring Session is redis-2.8.
2. Extract the archive file and go to the location as below.
\redis-2.8\bin\release\redis-2.8.17

3. Click on redis-server.exe to start the Redis server. Server will be started with default port 6379.
4. To run Redis command, click on the redis-cli.exe file. A command prompt will open and we can run the Redis command. For Redis command details visit the link.
5. Find some Redis commands.
a. To display all keys stored in Redis, use keys *
b. To delete all keys stored in Redis, use flushall

Project Structure in Eclipse with JavaConfig

Find the project structure in Eclipse with JavaConfig.
Spring Session + Redis + Servlet Integration Example

Gradle and Maven to Build Project

Find the gradle file to build the project.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
archivesBaseName = 'spring-session'
version = '0.0.1-SNAPSHOT'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.4.3.RELEASE'
    compile 'org.springframework.session:spring-session-data-redis:1.3.0.RELEASE'
    compile 'biz.paluch.redis:lettuce:3.5.0.Final'
    compile 'jstl:jstl:1.2'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.4.3.RELEASE'
} 
Find the maven file to build the project.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-session</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>spring-session</name>
        <description>Spring Project</description>	
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.3.RELEASE</version>
	</parent>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-data-redis</artifactId>
			<version>1.3.0.RELEASE</version>
		</dependency>		
		<dependency>
                       <groupId>biz.paluch.redis</groupId>
                       <artifactId>lettuce</artifactId>
                       <version>3.5.0.Final</version>
                </dependency> 
                <dependency>
	               <groupId>jstl</groupId>
	               <artifactId>jstl</artifactId>
	               <version>1.2</version>
                </dependency>              
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>						
	</dependencies> 
</project>  

Create Sample Servlet and JSP File for Spring Session Demo

We will create sample Servlet and JSP file for spring session demo.
HomeServlet.java
package com.concretepage;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String attributeName = req.getParameter("attributeName");
		String attributeValue = req.getParameter("attributeValue");
                //add attribute in HttpSession
		req.getSession().setAttribute(attributeName, attributeValue);
		resp.sendRedirect(req.getContextPath() + "/");
	}
} 
index.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
	<title>Spring Session with Servlet</title>
</head>
<body>
    <h3>Add Session Attribute</h3>
    <form action="./home" method="POST">
	Attribute Name :  <input type="text" name="attributeName"/><br/>
	Attribute Value : <input type="text" name="attributeValue"/><br/><br/>
	                  <input type="submit" value="Add Attribute"/>
    </form>
	<c:if test="${sessionScope.size() gt 0}">
	  <h3>Session Attribute Details</h3>
	  <table>
		<tr>
			<th>Attribute Name</th>
			<th>Attribute Value</th>
		</tr>
		<c:forEach items="${sessionScope}" var="attb">
			<tr>
				<td><c:out value="${attb.key}"/></td>
				<td><c:out value="${attb.value}"/></td>
			</tr>
		</c:forEach>
	  </table>
        </c:if>
</body>
</html> 
We are doing a simple task here. In JSP, user will enter session attribute name and value and submit the form. Servlet will access those values and call setAttribute() of HttpSession. But values are not being persisted in Tomcat Servlet container. Session values are being persisted in Redis. Spring session creates a cookie named as SESSION in browser that contains the id of our session.

Create JavaConfig for LettuceConnectionFactory with @EnableRedisHttpSession

Lettuce is an advanced Redis client that is used for thread safe synchronous, asynchronous and reactive usage. It supports Cluster, Sentinel, Pipelining, and codecs. Lettuce allows sharing one connection by multiple threads if they avoid blocking.
AppConfig.java
package com.concretepage;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@EnableRedisHttpSession 
public class AppConfig {
	@Bean
	public LettuceConnectionFactory connectionFactory() {
		return new LettuceConnectionFactory();
	}
}  
LettuceConnectionFactory : It is a connection factory that creates Lettuce based connections. We get LettuceConnection instance for every call of getConnection() method of LettuceConnectionFactory class. Multiple LettuceConnection instances share a single thread safe native connection by default. This shared native connection is never closed by the LettuceConnection instance and hence while calling getConnection() method, connection is not validated by default. If required we can change this behavior by using setValidateConnection(true) method of LettuceConnectionFactory while instantiating it.

@EnableRedisHttpSession: This annotation is added to configuration class. Using this annotation, it automatically adds @Configuration to the configuration class. It exposes a bean of SessionRepositoryFilter with bean name springSessionRepositoryFilter that will be backed by Redis. We have also to provide RedisConnectionFactory implementation bean. In our example we are using Lettuce based connection, so we have created a bean of LettuceConnectionFactory class.

Create Application Initializer with AbstractHttpSessionApplicationInitializer

To load our application configuration AppConfig class, find the application initializer class.
AppInitializer.java
package com.concretepage;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
public class AppInitializer extends AbstractHttpSessionApplicationInitializer {
	public AppInitializer() {
		super(AppConfig.class);
	}
} 
AbstractHttpSessionApplicationInitializer is the implementation of spring WebApplicationInitializer interface. It performs following task.
1. It registers DelegatingFilterProxy to use springSessionRepositoryFilter before any other registered Filter .
2. It also registers spring ContextLoaderListener .
3. It ensures that our servlet will use springSessionRepositoryFilter for every request that is responsible for replacing HttpSession implementation by custom implementation backed by Redis.

Project Structure in Eclipse with XML

Find the project structure in Eclipse with XML configuration.
Spring Session + Redis + Servlet Integration Example

Create Spring Application Context XML File for RedisHttpSessionConfiguration and LettuceConnectionFactory

Find spring application context XML file to configure spring session.
app-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
   <context:annotation-config/>
   <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
   <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>   
</beans> 
1. RedisHttpSessionConfiguration exposes a bean of SessionRepositoryFilter with bean name springSessionRepositoryFilter backed by Redis. SessionRepositoryFilter implements Filter and replaces the HttpSession implementation to be backed by Spring Session.
2. We should use <context:annotation-config/> because Spring Session does not provide Spring XML Namespace configuration right now. Get more information from the link .
3. Create a bean of LettuceConnectionFactory that implements RedisConnectionFactory. The role of RedisConnectionFactory is connecting Spring Session to Redis Server on default port 6379 .

Create web.xml

Create web.xml file.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

        <display-name>Spring Session with Servlet</display-name> 
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/app-config.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<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>
</web-app>   
1. To configure spring application context XML file i.e app-config.xml in our example, we need to configure contextConfigLocation using <context-param>. Configure ContextLoaderListener that will read contextConfigLocation and will pick up our app-config.xml file.

2. In app-config.xml file we have configured RedisHttpSessionConfiguration that exposes a bean of SessionRepositoryFilter with bean name springSessionRepositoryFilter backed by Redis, responsible for replacing the HttpSession implementation to be backed by Spring Session. Now we need to ensure that Servlet Container uses our springSessionRepositoryFilter for every request. So we need to configure springSessionRepositoryFilter mapping.

3. Spring DelegatingFilterProxy will look up a bean with the name springSessionRepositoryFilter that casts a filter backed by Spring Session. Hence for every request that invokes DelegatingFilterProxy will invoke springSessionRepositoryFilter.

Run Application

To run the project, follow below steps.
1. Download the source code using download link given below on this page.
2. Using command prompt, go to the root directory of the project and run following command. For Gradle, use below command.
gradle clean build
We will get WAR file inside build\libs directory. For Maven, use below command.
mvn clean package
We will get WAR file inside target directory. Now deploy WAR file in tomcat and access the URL as follows.
http://localhost:8080/spring-session/
Add some session attribute names and values. Find the print screen.
Spring Session + Redis + Servlet Integration Example
If we check values in Redis, we will get our session id. Find the print screen.
Spring Session + Redis + Servlet Integration Example
Now if we check browser cookie for localhost domain, we will get a cookie named as SESSION and this cookie will keep same session id as stored in Redis.
Spring Session + Redis + Servlet Integration Example
If we delete the session id from Redis, then we will observe that sessions attributes values will also be deleted from the application session.

I am done now. Happy Spring Session Learning!

References

Spring Session - HttpSession (JavaConfig)
Spring Session - HttpSession (XML Configuration)

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
FIND MORE TUTORILAS





Copyright ©2017 concretepage.com, all rights reserved |Privacy Policy | Contact Us