The document discusses Spring Session, which provides a way to store and configure session data handling in a platform-independent manner. It introduces Spring Session's architecture and components, including the SessionRepositoryFilter, SessionRepository implementations, and HttpSession wrappers. It then outlines the steps to use Spring Session with Redis for session persistence, including configuration of the RedisConnectionFactory, session usage, and bootstrap of SpringSession.
@dgomezg
Agenda
• Session Data: State of the art
• Spring-‐Session: Motivations & Goals
• Out of the box integration with Redis
• Use Cases
• Change persistent store
• Multiple user login handling
• Adding session to RESTful APIs
@dgomezg
Session Data: State of the art.
• HttpSession as data container
• Retrieved from the HttpServletRequest
• Implementation dependent on servlet
container
• Persistency configurable on servlet
container
@dgomezg
Spring Session Goals
•Provide a mechanism to store & configure
session data handling
• Platform independent
• Transparent to standard HttpSession usage
• Easily configurable
• Easily extensible
• New persistence mechanisms
@dgomezg
How it works
Session is accessed via HttpRequest
@RequestMapping("/user/session")
public String addToSession(HttpServletRequest request,
@RequestParam("attr") String attribute,
@RequestParam("val") String value) {
HttpSession session = request.getSession();
session.setAttribute(attribute, value);
return "redirect:/";
}
The Goal: intercept the Session access to
replace the Session creation by a richer implementation
@dgomezg
SessionRepositoryRequestWrapper
Overrides methods that return an HttpSession
•Encapsulates creation of specific HttpSession
•Handles HttpSession persistence (if any)
private final class SessionRepositoryRequestWrapper
extends HttpServletRequestWrapper {
@Override
public HttpSession getSession(boolean create) {/* Impl omitted */}
@Override
public HttpSession getSession() {/* Impl omitted */}
}
13.
@dgomezg
HttpSessionWrapper
Specific HttpSession implementation
•Transparent interface for the Application
•Independent from Servlet Container
•Spring-‐Session and Spring-‐Repository aware
private final class HttpSessionWrapper implements HttpSession {
}
14.
@dgomezg
SessionRepositoryFilter
Bootstraps Spring Session architecture
Should be placed first in the Filter Chain
Bean name is mandatory:
• springSessionRepositoryFilter
<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>
</filter-mapping>
15.
@dgomezg
SessionRepositoryFilter
Bootstraps Spring Session architecture
Servlet 3.0:
Use AbstractHttpSessionApplicationInitializer
public class Initializer
extends AbstractHttpSessionApplicationInitializer {
public Initializer() {
super(Config.class);
}
}
@dgomezg
Components needed
• SpringSessionFilter (already implemented)
• A SessionRepository implementation
• A redis backed implementation out-‐of-‐the-‐
box
• A persistence service (optional)
• (i.e) an external redis service
@dgomezg
Step 2: Import Redis Configuration
<context:annotation-config/>
<bean
class="org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"/>
RedisHttpSessionConfiguration configures:
• SessionRepositoryFilter
• A SessionRepository that persists to redis
• needs a RedisConnectionFactory
spring/session.xml
21.
@dgomezg
Step 2: Import Redis Configuration
@EnableRedisHttpSession
//@Import(RedisHttpSessionConfiguration.class)
public class Config {
}
RedisHttpSessionConfiguration configures:
• SessionRepositoryFilter
• A SessionRepository that persists to redis
• needs a RedisConnectionFactory
22.
@dgomezg
Step 3: RedisConnectionFactory
<beanid="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:hostName="${redis.host}" p:port="${redis.port}"
p:password="${redis.pass}"/>
<context:property-placeholder location="classpath:redis.properties"/>
Using Jedis client
• Defined in spring-‐data-‐redis.jar
Configures the external connection to Redis server
spring/redis.xml
23.
@dgomezg
Step 3: RedisConnectionFactory
@Bean
publicJedisConnectionFactory connectionFactory(
@Value("${spring.redis.host") String host,
@Value(“${spring.redis.port}”) int port,
@Value("${spring.redis.pass}") String pass) {
JedisConnectionFactory connection = new JedisConnectionFactory();
connection.setHostName(host);
connection.setPort(port);
connection.setPassword(pass);
return connection;
}
Using Jedis client
• Defined in spring-‐data-‐redis.jar
Configures the external connection to Redis server
24.
@dgomezg
Step 3b: RedisConnectionFactory
@EnableEmbeddedRedis// @Import(EmbeddedRedisConfiguration.class)
@EnableRedisHttpSession
public class Config {
@Bean
public JedisConnectionFactory connectionFactory(
@RedisServerPort int port) {
JedisConnectionFactory connection =
new JedisConnectionFactory();
connection.setPort(port);
return connection;
}
}
An embedded Redis Configuration is available in
spring-‐session-‐samples project
25.
@dgomezg
Step 4: Session usage
@Controller
public class SessionDataController {
@RequestMapping("/user/session")
public String addToSession(HttpServletRequest request,
@RequestParam("attr") String attribute,
@RequestParam("val") String value) {
HttpSession session = request.getSession();
session.setAttribute(attribute, value);
return "redirect:/";
}
}
Use your HttpSession as usual
(through HttpServletRequest)
26.
@dgomezg
Step 5: Bootstrap SpringSession
public class Initializer
extends AbstractHttpSessionApplicationInitializer {
public Initializer() {
super(Config.class);
}
}
Define a DelegatingFilterProxy with specific name
springSessionRepositoryFilter
@dgomezg
Further customization
• Out of the box impl. implies:
• MaxInactiveInterval = 30 min
• Session id exchanged through cookies
(SessionStrategy)
• SessionStore:
RedisOperationsSessionRepository
• RedisSerialization
• All defined in RedisHttpSessionConfiguration
31.
@dgomezg
Default inactive time
•Configurable as property in
RedisHttpSessionConfiguration
<context:annotation-config/>
<bean
class=“org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"
p:maxInactiveIntervalInSeconds="3600"/>
spring/session.xml
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class Config {
}
32.
@dgomezg
Session Strategy
Configures the policy to exchange the session Id.
Two implementations:
•CookieSessionStrategy (default)
•HeaderHttpSessionStrategy
<context:annotation-config/>
<bean
class=“org.springframework.session.data.redis.config.annotation.web.ht
tp.RedisHttpSessionConfiguration"
p:maxInactiveIntervalInSeconds="3600"/>
spring/session.xml
@dgomezg
CookieSessionStrategy
Can be customised to change cookie name
<context:annotation-config/>
<bean id="httpSessionStrategy"
class="org.springframework.session.web.http.CookieHttpSessionStrategy"
p:cookieName="UserSessionID"/>
<bean class=“o.s.s.d.r.c.annotation.web.http.RedisHttpSessionConfiguration"
p:httpSessionStrategy-ref=“httpSessionStrategy”/>
spring/session.xml
35.
@dgomezg
HeaderHttpSessionStrategy
Session id is specified on request headers
• x-‐auth-‐token by default
• header name can be modified
<context:annotation-config/>
<bean id="httpSessionStrategy"
class="org.springframework.session.web.http.HeaderHttpSessionStrategy"
p:headerName=“x-auth-token“/>
<bean class=“o.s.s.d.r.c.annotation.web.http.RedisHttpSessionConfiguration"
p:httpSessionStrategy-ref=“httpSessionStrategy”/>
spring/session.xml
36.
@dgomezg
Your own Strategy
Other strategies can be implemented & plugged
Implement HttpSessionStrategy
public interface HttpSessionStrategy {
String getRequestedSessionId(HttpServletRequest request);
void onNewSession(Session session,
HttpServletRequest request,
HttpServletResponse response);
void onInvalidateSession(HttpServletRequest request,
HttpServletResponse response);
}
@dgomezg
Customize SessionStorage
Different storage options could be implemented.
1) Implement a SessionRepository
public interface SessionRepository<S extends Session> {
S createSession();
void save(S session);
S getSession(String id);
void delete(String id);
}
39.
@dgomezg
Customize SessionStorage
Different storage options could be implemented.
2) Inject to SessionRepositoryFilter constructor
public class SessionRepositoryFilter<S extends ExpiringSession>
extends OncePerRequestFilter {
/* … */
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
if(sessionRepository == null) {
throw new IllegalArgumentException("SessionRepository cannot be null");
}
this.sessionRepository = sessionRepository;
}
}
@dgomezg
Multiple Session handling
Session id is :
1) exchanged with the client via CookieSessionStrategy
2) which is a MultipleSessionStrategy
3) so, different session IDs are kept.
43.
@dgomezg
Multiple Session handling
Session id is :
1) exchanged with the client via CookieSessionStrategy
2) which is a MultipleSessionStrategy
3) so, different session IDs are kept.
4) all we have to do is specify/select the right one.
@dgomezg
New Session
if index is found in array, session id is used
otherwise, new session is created
<a id="addAccount" href=“http://localhost:8080/?_s=17“>
Add Account
</a>
46.
@dgomezg
Compose new Session URL
We can create the new Session through the
HttpSessionManager
<a id=“addAccount" href=“${addAccountUrl}”/>
Add Account
</a>
HttpSessionManager sessionManager =
(HttpSessionManager)
httpRequest.getAttribute(HttpSessionManager.class.getName());
String addAlias = sessionManager.getNewSessionAlias(httpRequest);
httpRequest.setAttribute(“addAccountUrl",
sessionManager.encodeURL(contextPath, addAlias));
47.
@dgomezg
Using session index in URLs
HttpServletResponseWrapper automatically
encodes the session id in URL.
class CookieSessionStrategy.MultiSessionHttpServletResponse
extends HttpServletResponseWrapper {
@Override
public String encodeURL(String url) {
url = super.encodeURL(url);
String alias = getCurrentSessionAlias(request);
return
CookieHttpSessionStrategy.this.encodeURL(url, alias);
}
}
@dgomezg
State in RESTful APIs
We could add State to REST endpoints:
• Persisted on external persistent service (redis)
• Restored into the HttpSession by the filter
• Used trasparently
@dgomezg
HeaderHttpSessionStrategy
Uses an specific header in Response to return session
ID
By default x-‐auth-‐token
@Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
@dgomezg
HeaderHttpSessionStrategy
Session header name can be customised
@Bean
public HttpSessionStrategy httpSessionStrategy() {
HeaderHttpSessionStrategy sessionStrategy =
new HeaderHttpSessionStrategy();
sessionStrategy.setHeaderName("x-custom-session-id");
return sessionStrategy;
}
@dgomezg
Conclusions
•HttpSession not container dependant
•Implementation
•Configuration
•Persistent store easily configurable
•Transparent for the developer
•SpringSessionFilter,
•HttpServletRequest/HttpSession Wrappers