Spring Session加Redis

栏目: Java · 发布时间: 7年前

内容简介:Spring Session加Redis

= 8

本文出自:【InTheWorld的博客】

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 中出现如下的内容:

Spring Session加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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网络机器人Java编程指南

网络机器人Java编程指南

美 Heaton J. / 电子工业出版社 / 2002-7 / 44.00元

这是一本研究如何实现具有Web访问能力的网络机器人的书。该书从Internet编程的基本原理出发,深入浅出、循序渐进地阐述了网络机器人程序Spider、Bot、Aggregator的实现技术,并分析了每种程序的优点及适用场合。本书提供了大量的有效源代码,并对这些代码进行了详细的分析。通过本书的介绍,你可以很方便地利用这些技术,设计并实现网络蜘蛛或网络信息搜索器等机器人程序。 适合于具有一起来看看 《网络机器人Java编程指南》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试