Spring Session加Redis(山东数漫江湖)
session是一个非常常见的概念。session的作用是为了辅助http协议,因为http是本身是一个无状态协议。为了记录用户的状态,session机制就应运而生了。同时session也是一个非常老的概念了,使用session的方法也是多种多样。就Java来说,servlet的标准本身是包含session的,Tomcat会把session的信息存储在服务器内存里,Request提供了获取session的方法。
然而,前文所述的session机制其实是有不少缺点的。首先就是session数据没有一定的持久化机制,而且难以实现应用服务器的水平扩展。在负载均衡器 + 应用服务器集群的架构中,session共享是一个基本的要求。在Spring生态圈里,也有Spring session完成session存储和共享的功能。Spring Session支持把session信息以各种形式存储,比如数据库或者Redis。个人认为,Redis比RDBMS更加适合session数据的存储。首先,session数据都是有时效性的,Redis的数据超时机制可以很好的完成session信息的清除;此外,Redis的数据访问速度更快,对于时效性较强的session数据,会有比较好的加速效果。
由于注解的存在,在Spring项目中增加Spring Session Redis是非常的简单的:
1. 增加Spring Session以及Spring Data Redis的依赖
compile 'org.springframework.session:spring-session:1.3.0.RELEASE' compile 'org.springframework.boot:spring-boot-starter-data-redis'
2. 增加Spring Session Redis的配置
@EnableRedisHttpSession
public class HttpSessionConfig {
@Bean
public RedisConnectionFactory connectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.setPort(6379);
connectionFactory.setHostName("localhost");
return connectionFactory;
}
}
然后就完成了,实在是太简单了。在浏览器中进行请求,然后可以发现Redis中出现如下的内容:
先不解释Redis中存储的数据的具体含义,我们先来研究一下,@EnableRedisHttpSession 的注解到底帮我们做了什么。所以,看源码走起咯。。。
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {
/* */
}
这个注解包含了一个重要的@Import注解,@Import注解支持导入普通的java类,并将其声明成一个bean。所以使用了@EnableRedisSession之后,就相当于同时声明了一个RedisHttpSessionConfiguration的bean。然后看看,这个类是如何定义的:
@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements EmbeddedValueResolverAware, ImportAware {
@Bean
public RedisTemplate<Object, Object> sessionRedisTemplate(
RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
if (this.defaultRedisSerializer != null) {
template.setDefaultSerializer(this.defaultRedisSerializer);
}
template.setConnectionFactory(connectionFactory);
return template;
} @Bean
public RedisOperationsSessionRepository sessionRepository(
@Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate,
ApplicationEventPublisher applicationEventPublisher) {
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
sessionRedisTemplate);
sessionRepository.setApplicationEventPublisher(applicationEventPublisher);
sessionRepository
.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
if (this.defaultRedisSerializer != null) {
sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
} String redisNamespace = getRedisNamespace();
if (StringUtils.hasText(redisNamespace)) {
sessionRepository.setRedisKeyNamespace(redisNamespace);
} sessionRepository.setRedisFlushMode(this.redisFlushMode);
return sessionRepository;
} }
RedisHttpSessionConfiguration中声明了几个重要的bean,上面的代码片段其实就是实现了Redis相关的配置。其中的依赖关系为RedisOperationsSessionRepository =>sessionRedisTemplate => RedisConnectionFactory。同时RedisHttpSessionConfiguration继承于SpringHttpSessionConfiguration。而SpringHttpSessionConfiguration本身会申明一个springSessionRepositoryFilter,这个filter作用于全局,session的保存和失效都是在这里完成的。对于这个filter的具体实现,这里先不作分析,因为它本身还是通过调用RedisOperationsSessionRepository来操作Redis实现session的保存的。
RedisOperationsSessionRepository实现代码其实还挺多的,但是逻辑却都不复杂,所以没有必要贴很多代码。就看看Session保存的函数吧!
public void save(RedisSession session) {
session.saveDelta();
if (session.isNew()) {
String sessionCreatedKey = getSessionCreatedChannel(session.getId());
this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
session.setNew(false);
}
}
并没有太多东西,sessionRedisOperations.convertAndSend()完成了session数据的保存。那么Redis中的session数据是如何存储的呢?对于一个session数据,会在Redis存两个key/value,其中一个存储实际的session数据,另外一个用于辅助session过期的处理。此外还有一个总体的数据,用于记录过期的session。下面是一个典型的存储形式:
* HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2
* EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
* APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
* EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
* SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
* EXPIRE spring:session:expirations1439245080000 2100
第一条的存储命令就是实际的session数据,这个数据在Redis是以HashSet的形式存储的,可以在里面存储各种数据。第三条存储命令就是辅助session过期的数据,它在expire时间会比实际数据久一点,用于区别一个session是超时还是不存在。第五条存储命令就是整体的session过期记录,它是一个集合。这个整体expirations集合的意义在于Redis的超时是不精确的,可能会出现一个session已经过期(辅助session数据也已经过期)了,但是它仍然存在于Redis中。这是因为Redis的数据超时清除任务是低优先级的。有了整体的session过期记录,就可以解决这种问题。当Redis真正清除数据时(会有事件通知),再把session从expirations集合中删除掉。
Spring Session加Redis(山东数漫江湖)的更多相关文章
- Spring Session加Redis
session是一个非常常见的概念.session的作用是为了辅助http协议,因为http是本身是一个无状态协议.为了记录用户的状态,session机制就应运而生了.同时session也是一个非常老 ...
- Spring归纳小结(山东数漫江湖)
前言 如果说有什么框架是Java程序员必然会学习.使用到的,那么Spring肯定是其中之一.本篇博客,将根据博主在日常工作中对Spring的使用做一个系统的归纳小结. Spring的一些概念和思想 S ...
- Spring 事务管理(山东数漫江湖)
最新又重新学习了一遍Spring的事务,这里做点总结,不做如何一步步配置的流水账. 1. 关键类 public interface PlatformTransactionManager { Trans ...
- 深入分析Spring 与 Spring MVC容器(山东数漫江湖)
1 Spring MVC WEB配置 Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext, ...
- Spring cookie 实战(山东数漫江湖)
Cookie是什么 简单来说,cookie就是浏览器储存在用户电脑上的一小段文本文件.cookie 是纯文本格式,不包含任何可执行的代码.一个web页面或服务器告知浏览器按照一定规范来储存这些信息,并 ...
- 使用Spring Session和Redis解决分布式Session跨域共享问题
http://blog.csdn.net/xlgen157387/article/details/57406162 使用Spring Session和Redis解决分布式Session跨域共享问题
- 170222、使用Spring Session和Redis解决分布式Session跨域共享问题
使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...
- Spring4+SpringMVC+MyBatis整合思路(山东数漫江湖)
1.Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListener,并指定spring加载配置文件 ...
- Spring Session - 使用Redis存储HttpSession例子
目的 使用Redis存储管理HttpSession: 添加pom.xml 该工程基于Spring Boot,同时我们将使用Spring IO Platform来维护依赖版本号: 引入的依赖有sprin ...
随机推荐
- scrapy(2)——scrapy爬取新浪微博(单机版)
Sina爬虫教程 Scrapy环境搭建 环境:window10 + python2.7(包含scrapy)+ mongoDB 1.1 安装集成了python2.7的anaconda ana ...
- iOS- 移动端Socket UDP协议广播机制的实现
1.前言 什么是UDP协议广播机制? 举一个例, 例如在一群人群中,一个人要找张三,于是你向人群里大喊一声(广播):“谁是张三” 如果它是张三,它就会回应你,在网络中也是一样的. ...
- css那些事儿3 列表与浮动
一 列表 列表默认为行内块元素,具有宽高,当一个非块元素是无法应用宽高的,比如a 1 有序列表 有ol li组成,其中li为列表项,列表的ol子元素务必为li元素标签,li子内容支持列表任意嵌套,有 ...
- jconsole工具监控数据分析
当Jconsole连接成功后,它从JMX获取信息,我们便可以在里面监控具体的内容.Jconsole能捕获到以下信息: 概述 - JVM概述和一些监控变量的信息 内存 - 内存的使用信息 线程 - 线程 ...
- ASP.NET MVC4计划任务实现方法(定时执行某个功能)
系统中定时执行某个任务是比较常用的功能,如一个部门定期向上级部门上报数据是一个典型的例子,下面就简单说说在.net mvc中如何实现定时执行某个功能的方法. 1.首先修改Glocal.asax文件,在 ...
- RT-thread内核之对象管理系统
一.数据结构 1.对象控制块:在include/rtdef.h中定义 /** * Base structure of Kernel object */ struct rt_object { char ...
- NetScaler VLAN’s Demystified
NetScaler VLAN’s Demystified https://www.citrix.com/blogs/2014/12/29/netscaler-vlans-demystified/ Th ...
- 【刷题】BZOJ 2882 工艺
Description 小敏和小燕是一对好朋友. 他们正在玩一种神奇的游戏,叫Minecraft. 他们现在要做一个由方块构成的长条工艺品.但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工 ...
- BZOJ4827:[AH2017/HNOI2017]礼物——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4827 https://www.luogu.org/problemnew/show/P3723 题面 ...
- TCP中三次握手建立和四次握手释放以及相关问题
本文基于个人所学和网上博文所整理,若有不妥处,欢迎留言指出 TCP连接过程中标志位的意义: 字符缩写 描述 SYN 同步序号,表示此报文是一个连接请求或连接接受报文 ACK 确认位,对接收到的报文的确 ...