Spring Session Implementation Guide: Session Sharing with Redis in Distributed Systems
Spring Session enables distributed session sharing by storing HTTP session data in Redis, using a filter and listener configuration to replace Tomcat’s in‑memory storage, managing three Redis keys with coordinated expirations, and subscribing to keyspace events for reliable cleanup and cross‑instance access.
HTTP protocol is stateless by design. To maintain session information, browsers use cookies with SessionID to identify session requests, and servers store session data using SessionID as the key. In single-instance applications, sessions can be stored in the application process itself. However, as application scale grows and horizontal scaling is required, multi-instance session sharing becomes a challenge.
Spring Session is designed to solve the multi-process session sharing problem. This article explains how to use Spring Session and its working principles.
1. Background
When applications are deployed on Tomcat, sessions are maintained in Tomcat's memory. If an application is deployed on multiple instances, sessions cannot be shared. Spring Session solves the session sharing problem in distributed scenarios.
2. Usage Method
Spring Session supports storage in Hazelcast, Redis, MongoDB, and relational databases. This article focuses on Redis storage.
web.xml configuration:
springSessionRepositoryFilter
org.springframework.web.filter.DelegatingFilterProxy
springSessionRepositoryFilter
/*Spring main configuration:
p:poolConfig-ref="jedisPoolConfig"3. Working Process
Tomcat web.xml parsing sequence: Listener → Filter → Servlet.
1) SessionRepositoryFilter is loaded into the Spring container through Tomcat's listener. The RedisHttpSessionConfiguration in the Spring configuration file generates SessionRepositoryFilter in its parent class SpringHttpSessionConfiguration:
@Bean
public
SessionRepositoryFilter
springSessionRepositoryFilter(
SessionRepository
sessionRepository) {
......
return sessionRepositoryFilter;
}2) Filter initialization: The filter configured in web.xml is DelegatingFilterProxy. DelegatingFilterProxy retrieves the springSessionRepositoryFilter from the Spring container during initialization:
protected void initFilterBean() throws ServletException {
synchronized (this.delegateMonitor) {
if (this.delegate == null) {
if (this.targetBeanName == null) {
this.targetBeanName = getFilterName();
}
WebApplicationContext wac = findWebApplicationContext();
if (wac != null) {
this.delegate = initDelegate(wac);
}
}
}
}SessionRepositoryFilter core workflow:
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
//Wraps HttpServletRequest, overrides getSession(boolean create) method
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
request, response, this.servletContext);
......
try {
filterChain.doFilter(strategyRequest, strategyResponse);
}
finally {
//Ensure session persistence
wrappedRequest.commitSession();
}
}4. Caching Mechanism
Each session is stored in Redis with three keys:
spring:session:sessions - Hash structure storing main session content (creationTime, maxInactiveInterval, lastAccessedTime)
spring:session:sessions:expires - String structure storing an empty value
spring:session:expirations - Set structure storing session IDs that expire at specific timestamps
Redis has three key expiration strategies: timed deletion, lazy deletion, and periodic deletion. Redis uses lazy deletion and periodic deletion strategies. Relying solely on Redis's expiration policy for real-time key deletion is unreliable.
Spring Session uses three keys with different expiration times to ensure that when the expiration event is triggered, the session data can still be retrieved. The spring:session:sessions:expires key expires 5 minutes earlier than the other keys, allowing business logic to access session information after expiration.
Session cleanup scheduled task:
public void cleanExpiredSessions() {
long now = System.currentTimeMillis();
long prevMin = roundDownMinute(now);
......
String expirationKey = getExpirationKey(prevMin);
Set
sessionsToExpire = this.redis.boundSetOps(expirationKey).members();
this.redis.delete(expirationKey);
for (Object session : sessionsToExpire) {
String sessionKey = getSessionKey((String) session);
touch(sessionKey);
}
}
private void touch(String key) {
//Access the key to trigger lazy deletion
this.redis.hasKey(key);
}5. Event Subscription
By default, Spring Session subscribes to keyspace notifications (gxE). ConfigureNotifyKeyspaceEventsAction enables keyspace notifications:
public void configure(RedisConnection connection) {
String notifyOptions = getNotifyOptions(connection);
String customizedNotifyOptions = notifyOptions;
if (!customizedNotifyOptions.contains("E")) {
customizedNotifyOptions += "E";
}
boolean A = customizedNotifyOptions.contains("A");
if (!(A || customizedNotifyOptions.contains("g"))) {
customizedNotifyOptions += "g";
}
if (!(A || customizedNotifyOptions.contains("x"))) {
customizedNotifyOptions += "x";
}
if (!notifyOptions.equals(customizedNotifyOptions)) {
connection.setConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS, customizedNotifyOptions);
}
}RedisHttpSessionConfiguration registers event listeners:
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory connectionFactory,
RedisOperationsSessionRepository messageListener) {
......
//Subscribe to del and expired events
container.addMessageListener(messageListener,
Arrays.asList(new PatternTopic("__keyevent@*:del"),
new PatternTopic("__keyevent@*:expired")));
//Subscribe to created events
container.addMessageListener(messageListener, Arrays.asList(new PatternTopic(
messageListener.getSessionCreatedChannelPrefix() + "*")));
return container;
}Event subscription example:
@Component
public class SessionExpiredListener implements ApplicationListener
{
@Override
public void onApplicationEvent(SessionExpiredEvent event) {
......
}
}6. Summary
Spring Session provides an excellent solution for resource sharing in distributed environments. Based on Servlet specifications, it requires only simple configuration to implement session sharing, achieving low coupling with business logic. This design philosophy can be referenced in future project development.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.