参考资料:
http://projects.spring.io/spring-session/#quick-start
http://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html5/guides/httpsession.html#httpsession-sample
spring session提供以下功能:
1.API and implementations for managing a user's session
2.HttpSession - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way
2.1.Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.
2.2.Multiple Browser Sessions - Spring Session supports managing multiple users' sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).
2.3.RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs
3.WebSocket - provides the ability to keep the HttpSession alive when receiving WebSocket messages
仅是集群session功能,都是振奋人心的.spring session是通过filter嵌入去实现的(spring security也是使用这种方式),下面是个例子.
1.主要依赖
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>${slf4j.version}</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>${slf4j.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>${spring.version}</version>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-tx</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-aop</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context-support</artifactId>
- <version>${spring.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.data</groupId>
- <artifactId>spring-data-redis</artifactId>
- <version>1.4.1.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>redis.clients</groupId>
- <artifactId>jedis</artifactId>
- <version>2.5.2</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.session</groupId>
- <artifactId>spring-session</artifactId>
- <version>${spring.session.version}</version>
- </dependency>
2.写一个configuration来启用RedisHttpSession,在这个配置注册一个redis客户端的连接工厂Bean,供Spring Session用于与redis服务端交互.
- package org.exam.config;
- import org.springframework.context.annotation.Bean;
- import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
- import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
- /**
- * Created by xin on 15/1/20.
- */
- @EnableRedisHttpSession
- public class SessionConfig {
- @Bean
- public JedisConnectionFactory connectionFactory() {
- return new JedisConnectionFactory();
- }
- }
3.写一个Initializer,主要用于向应用容器添加springSessionRepositoryFilter.
- package org.exam.config;
- import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
- /**
- * Created by xin on 15/1/20.
- */
- public class SessionApplicationInitializer extends AbstractHttpSessionApplicationInitializer {
- }
4.将SessionConfig加入到org.exam.config.DispatcherServletInitializer#getRootConfigClasses
- @Override
- protected Class<?>[] getRootConfigClasses() {
- return new Class<?>[] {AppConfig.class,SessionConfig.class};
- }
5.使用例子.
- package org.exam.web;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- /**
- * Created by xin on 15/1/7.
- */
- @Controller
- public class DefaultController {
- @RequestMapping("/")
- public String index(Model model,HttpServletRequest request,String action,String msg){
- HttpSession session=request.getSession();
- if ("set".equals(action)){
- session.setAttribute("msg", msg);
- }else if ("get".equals(action)){
- String message=(String)session.getAttribute("msg");
- model.addAttribute("msgFromRedis",message);
- }
- return "index";
- }
- }
得到这个被spring session包装过的session,像平常一样直接使用.
6.测试.先启动redis服务端.
请求:localhost:8080/testweb/?action=set&msg=123 把123通过spring session set到redis去.
请求:localhost:8080/testweb/?action=get
从redis取出刚才存入的值.
从redis删除存入去相关的值,再次请求localhost:8080/testweb/?action=get查看结果
下面顺便跟踪下实现吧:
1.注册springSessionRepositoryFilter位置在:org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer#insertSessionRepositoryFilter,从org.springframework.web.filter.DelegatingFilterProxy#initDelegate可以看出会去找名为springSessionRepositoryFilter Bean的实现作为Filter的具体实现.
2.因为使用了@EnableRedisHttpSession,就会使用org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration,这个配置里注册的springSessionRepositoryFilter Bean就是SessionRepositoryFilter.即springSessionRepositoryFilter的实现为org.springframework.session.web.http.SessionRepositoryFilter
3.Filter每一次的请求都会调用doFilter,即调用SessionRepositoryFilter的父类OncePerRequestFilter的doFilter,此方法会调用SessionRepositoryFilter自身的doFilterInternal.这个方法如下:
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
- request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);
- SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response);
- SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);
- HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
- HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
- try {
- filterChain.doFilter(strategyRequest, strategyResponse);
- } finally {
- wrappedRequest.commitSession();
- }
- }
4.从这里就知request经过了包装,当然里面的getSession方法也重写了.org.springframework.session.web.http.SessionRepositoryFilter.SessionRepositoryRequestWrapper#getSession(boolean)方法如下:
- public HttpSession getSession(boolean create) {
- if(currentSession != null) {
- return currentSession;
- }
- String requestedSessionId = getRequestedSessionId();
- if(requestedSessionId != null) {
- S session = sessionRepository.getSession(requestedSessionId);
- if(session != null) {
- this.requestedValidSession = true;
- currentSession = new HttpSessionWrapper(session, getServletContext());
- currentSession.setNew(false);
- return currentSession;
- }
- }
- if(!create) {
- return null;
- }
- S session = sessionRepository.createSession();
- currentSession = new HttpSessionWrapper(session, getServletContext());
- return currentSession;
- }
即上面的例子调用getSession会调用此方法来获取Session.而此Session是通过sessionRepository创建的,此处注入的是org.springframework.session.data.redis.RedisOperationsSessionRepository(sessionRepository的注册也是在org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration),而不是应用服务器本身去创建的.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。