skip to content

Spring Session: Replication & ID

With sessions externalized, the id can travel in a cookie or a header, expiration is centrally managed, and any instance can serve any request. Interviewers ask about the header resolver because that is how a native mobile client participates.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

Why does Spring Session let you run multiple stateless app instances behind a load balancer, and what problem does it solve?

level: juniorimportance: must knowfreq 62%

answer

  1. HttpSession = one JVM's memory
  2. External shared store = any instance serves any request
  3. SessionRepositoryFilter swaps getSession()
  4. @EnableRedisHttpSession / starter
  5. Kills sticky sessions

basics

~20 s

By default an HTTP session lives in one server's memory, so a user must stick to that server. Spring Session stores sessions in a shared external store (Redis, JDBC), so any instance can read them.

solid answer

~40 s

A standard servlet HttpSession is held in the memory of the JVM that created it. With several app instances behind a load balancer, a request routed to a different instance won't find that session — you'd need sticky sessions, and losing an instance loses its sessions. Spring Session replaces the container's HttpSession with an implementation backed by an external store (Redis, Hazelcast, JDBC/database, MongoDB). All instances read/write the same store, so any instance can serve any request and the app becomes truly stateless at the JVM level. This enables horizontal scaling, rolling deploys, and failover without losing logged-in users. You enable it with @EnableRedisHttpSession (or @EnableJdbcHttpSession, etc.), and a SessionRepositoryFilter transparently swaps the session implementation.

code

java · 18 lines
java
@Configuration
@EnableRedisHttpSession // externalize HttpSession into Redis
public class SessionConfig {
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(
            new RedisStandaloneConfiguration("redis", 6379));
    }
}

// Controller code is unchanged — getSession() now hits Redis via the filter
@GetMapping("/visit")
public int visit(HttpSession session) {
    Integer n = (Integer) session.getAttribute("count");
    n = (n == null) ? 1 : n + 1;
    session.setAttribute("count", n); // written to shared store
    return n;
}

go deeper

for a junior

Know the core idea: sessions normally live in one server's memory; Spring Session puts them in a shared store so all instances can read them.

for a middle

Should name a backend (Redis/JDBC), the enabling annotation, and that SessionRepositoryFilter transparently swaps the session.

for a senior

Discuss serialization concerns, store HA, latency trade-offs, and Spring Security SecurityContext living in the session.

for a principal

Weigh session-in-store vs stateless-token architectures, store failure modes, and operational impact on deploys/autoscaling.

## The core problem A classic servlet **HttpSession** is an in-memory map living inside a single JVM (the app server / container). The server hands the browser a **session ID** in a cookie (`JSESSIONID` by default), and on each request looks that ID up in *its own* memory to restore the session. With one server this is fine. With **multiple instances behind a load balancer** it breaks: if instance A created the session but the load balancer routes the next request to instance B, B has no such session in memory and the user appears logged out. ### Traditional workarounds (and why they're weak) - **Sticky sessions (session affinity):** the load balancer pins each user to the instance that created their session. Works, but: losing an instance loses all its sessions; uneven load; and it complicates rolling deploys and autoscaling. - **Container-level replication:** app servers gossip session state to each other. Chatty, memory-heavy, and coupled to a specific server. ## What Spring Session does **Spring Session** externalizes session state into a **shared datastore** so every instance sees the same sessions. It does this without you rewriting code that calls `HttpServletRequest.getSession()`. Key moving parts: - **`SessionRepositoryFilter`** — a servlet `Filter` registered early in the chain. It wraps the incoming request so that any call to `getSession()` returns a Spring-managed session instead of the container's. This is the magic that makes the swap transparent. - **`SessionRepository<S>`** — the abstraction for load/save/delete of sessions. Concrete backends: `RedisSessionRepository` / `RedisIndexedSessionRepository`, `JdbcIndexedSessionRepository`, `HazelcastIndexedSessionRepository`, `MongoIndexedSessionRepository`. - **`Session`** — Spring's session interface (implemented by `MapSession`, `RedisSession`, etc.). - **Enabling annotations:** `@EnableRedisHttpSession`, `@EnableJdbcHttpSession`, `@EnableHazelcastHttpSession`, `@EnableMongoHttpSession` — or in Spring Boot, just add the starter (e.g. `spring-session-data-redis`) and set `spring.session.store-type` if needed; Boot auto-configures it. ## Why this yields "stateless" instances The JVM no longer *owns* any session data — it's just a stateless compute node reading/writing the shared store. That unlocks: - **Horizontal scaling:** add/remove instances freely; no sticky sessions required. - **Failover:** an instance can die mid-session; another serves the next request. - **Rolling / blue-green deploys:** restart instances without logging everyone out (as long as the store survives). ## Gotchas - **Serialization:** attributes you put in the session must be serializable to the store (Java serialization or JSON, depending on config). Non-serializable attributes will fail. - **The store becomes a dependency and a single point of failure** — it must itself be HA (e.g. Redis cluster/sentinel). - **Latency:** every session read/write is now a network hop, not a memory lookup. - **Spring Security integration:** Spring Security stores the `SecurityContext` in the session, so externalizing the session is exactly what makes clustered authentication work. ## When to use Any time you run more than one instance and keep server-side session state (logins, carts, CSRF tokens). If you're fully token-based/stateless (e.g. JWT with no server session), you may not need it at all.

  • Do you still need sticky sessions when using Spring Session with Redis?
    No — that's the point. Since every instance reads the same store, the load balancer can route freely. Sticky sessions can still slightly help latency/cache locality but aren't required for correctness.
  • What must be true of objects you store as session attributes?
    They must be serializable to the backing store's format (Java Serializable for default JDK serialization, or JSON-mappable if you configure a JSON serializer). Non-serializable attributes cause save failures.

saying these in an interview costs you the question

  • Thinking Spring Session requires code changes to every getSession() call (it doesn't — the filter handles it)
  • Believing the external store removes the need for it to be highly available
  • Confusing this with JWT/stateless tokens — Spring Session is still server-side session state

context

open as a page

Compare CookieHttpSessionIdResolver and HeaderHttpSessionIdResolver. When would you switch from cookies to a header?

level: middleimportance: must knowfreq 55%

basics

~20 s

An HttpSessionIdResolver decides how the session ID travels between client and server. The cookie resolver (default) uses a Set-Cookie/Cookie. The header resolver reads/writes it in an HTTP header (e.g. X-Auth-Token), which suits non-browser clients like mobile apps or SPAs across domains.

open as a page

How does session expiration work in a clustered Spring Session (Redis) setup, including timeout config and cleanup?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Each session has a max inactive interval (default 30 min). With Redis, the session key gets a TTL so it self-expires; an indexed repository additionally tracks expirations to fire SessionDeleted/SessionExpiredEvents. JDBC needs a scheduled cleanup job.

open as a page

How does Spring Session integrate with WebSocket connections, and why is that integration necessary?

level: seniorimportance: should knowfreq 30%

basics

~20 s

WebSocket connections are long-lived, so a session can expire while the socket stays open. Spring Session's WebSocket support keeps the session's last-accessed time updated on WebSocket activity and closes the socket when the session actually expires.

open as a page

You're designing a clustered Spring Session deployment. What are the key decisions and failure modes around serialization, the session store as a dependency, and consistency?

level: principalimportance: should knowfreq 24%

basics

~10 s

Decide the serializer (JDK vs JSON) since attributes must round-trip across versions; make the store highly available since it's now a shared dependency and SPOF; and accept eventual-consistency/latency trade-offs plus rolling-deploy serialization compatibility.

open as a page