普通单服务器web应用中,Session都是由容器管理,存放到内存中。如果搭建分布式集群,就需要保证
各个服务器中所使用的Session一致。比较简单的方式就是设计一个Filter,利用HttpServletRequestWrapper,
直接将Session换成自己管理。这也就是spring-session的设计思路。
1、介绍
GitHub地址:https://github.com/spring-projects/spring-session
2、简单实例
1)增加依赖jar
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.4.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.5.2</version> </dependency> <!-- Spring Session --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>1.2.0.RELEASE</version> <type>pom</type> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency>
2)编写一个配置类,用来启用RedisHttpSession功能,并向Spring容器中注册一个RedisConnectionFactory,并增加session监听器
@EnableRedisHttpSession(maxInactiveIntervalInSeconds=3000) public class Config { @Bean public JedisConnectionFactory connectionFactory() { RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster") .sentinel("192.168.191.11", 26379).sentinel("192.168.191.11", 26479).sentinel("192.168.191.11", 26579); JedisConnectionFactory jcf = new JedisConnectionFactory(sentinelConfig); jcf.setPassword("123456"); return jcf; } /** * 自定义session监听器 * @return */ @Bean public ApplicationListener sessionListener(){ return new SessionListener(); } }
由于不再使用web容器所管理的session,原有通过web.xml中增加配置设置session时效,及session监听的方式也不再适用。可使用maxInactiveIntervalInSeconds来设置session失效时间,单位(秒)。
3)由于spring-session将session的事件注册到ApplicationEvent中,可以使用自定监听器用来监听
public class SessionListener implements ApplicationListener<AbstractSessionEvent> { @Override public void onApplicationEvent(AbstractSessionEvent event) { if (event instanceof SessionCreatedEvent) { System.out.println("创建session"); } if (event instanceof SessionDestroyedEvent) { System.out.println("销毁session"); } } }
4)将RedisHttpSessionConfig及监听器加入spring容器中
public class Initializer extends AbstractHttpSessionApplicationInitializer { public Initializer() { super(Config.class); } }
5)测试servlet
@WebServlet("/session") public class SessionServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getSession().setAttribute("A", "test"); resp.sendRedirect(req.getContextPath() + "/"); } private static final long serialVersionUID = 2878267318695777395L; }
启动工程,访问servlet地址。
Http Session数据在Redis中是以Hash结构存储的。
127.0.0.1:6379> keys * 1) "spring:session:expirations:1431577740000" 2) "spring:session:sessions:e2cef3ae-c8ea-4346-ba6b-9b3b26eee578"
可以看到,还有一个key="spring:session:expirations:1431577740000"的数据,是以Set结构保存的。这个值记录了所有session数据应该被删除的时间(即最新的一个session数据过期的时间)。
6)需要注意的就是redis需要2.8以上版本,然后开启事件通知,在redis配置文件里面加上
notify-keyspace-events Ex