Spring Session+Spring Data Redis 解决分布式系统架构中 Session 共享问题

一 简介

如题所示,在分布式系统架构中须要解决的一个很重要的问题就是——如何保证各个应用节点之间的Session共享。其实有一个很好的解决办法就是在redis、memcached等组件中独立存储全部应用节点的Session,以达到各个应用节点之间的Session共享的目的javascript

Spring Session提供了一种独立于应用服务器的方案,这种方案可以在Servlet规范以内配置可插拔的session数据存储,不依赖于任何应用服务器的特定API。这就意味着Spring Session可以用于实现了servlet规范的全部应用服务器之中(Tomcat、Jetty、 WebSphere、WebLogic、JBoss等),它可以很是便利地在全部应用服务器中以彻底相同的方式进行配置。同时咱们还能够选择任意最适应需求的外部session数据存储方式php

Spring Session为企业级Java应用的session管理带来了革新,使得如下的功能更加容易实现:java

  • 编写可水平扩展的原生云应用
  • 将session所保存的状态保存到特定的外部session存储中,如Redis或Apache Geode中,它们可以以独立于应用服务器的方式提供高质量的集群
  • 当用户使用WebSocket发送请求的时候,可以保持HttpSession处于活跃状态
  • 在非Web请求的处理代码中,可以访问session数据,好比在JMS消息的处理代码中
  • 支持每一个浏览器上使用多个session,从而可以很容易地构建更加丰富的终端用户体验
  • 控制session id如何在客户端和服务器之间进行交换,这样的话就能很容易地编写Restful API,由于它能够从HTTP 头信息中获取session id,而没必要再依赖于cookie

须要说明的很重要的一点就是,Spring Session的核心项目并不依赖于Spring框架,因此,咱们甚至可以将其应用于不使用Spring框架的项目中web

二 代码示例

其实,咱们想要在项目中使用Spring Session须要作的工做并很少,只须要作到如下几步便可:redis

(1)引入相关jar包:

这里须要引入Spring Session和Spring Data Redis相关的依赖jar包。能够自行从maven仓库下载,也能够参考我使用的jar包:down.51cto.com/data/228183…spring

(2)修改spring-data-redis相关配置:

在项目的spring-data-redis相关配置中添加如下配置:浏览器

<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--超时时间,默认1800秒-->
        <property name="maxInactiveIntervalInSeconds" value="1800" />
    </bean>复制代码

完整的context_redis_cluster.xml文件以下:tomcat

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <description>spring-data-redis-cluster</description>

    <!-- 配置Cluster -->
    <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <property name="maxRedirects" value="${redis.cluster.maxRedirects}" />
        <!-- 节点配置 -->
        <property name="clusterNodes">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host1}" />
                    <constructor-arg name="port" value="${redis.cluster.port1}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host2}" />
                    <constructor-arg name="port" value="${redis.cluster.port2}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host3}" />
                    <constructor-arg name="port" value="${redis.cluster.port3}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host4}" />
                    <constructor-arg name="port" value="${redis.cluster.port4}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host5}" />
                    <constructor-arg name="port" value="${redis.cluster.port5}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host6}" />
                    <constructor-arg name="port" value="${redis.cluster.port6}" />
                </bean>
            </set>
        </property>
    </bean>

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.cluster.jedisPoolConfig.maxTotal}" />
        <property name="maxIdle" value="${redis.cluster.jedisPoolConfig.maxIdle}" />
        <property name="maxWaitMillis" value="${redis.cluster.jedisPoolConfig.maxWaitMillis}" />
        <property name="testOnBorrow" value="${redis.cluster.jedisPoolConfig.testOnBorrow}" />
    </bean>

    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg ref="redisClusterConfiguration" />
        <constructor-arg ref="jedisPoolConfig" />
        <property name="password" value="${redis.cluster.jedisConnectionFactory.password}" />
    </bean>

    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    <bean id="jdkSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory">
        <!-- 序列化方法 -->
        <property name="keySerializer" ref="stringRedisSerializer" />
        <property name="hashKeySerializer" ref="stringRedisSerializer" />
        <property name="valueSerializer" ref="jdkSerializer" />
        <property name="hashValueSerializer" ref="jdkSerializer" />
    </bean>

    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="jedisConnectionFactory" />

    <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--超时时间,默认1800秒-->
        <property name="maxInactiveIntervalInSeconds" value="1800" />
    </bean>
</beans>复制代码

注:对应的属性文件是:服务器

#Redis Cluster
redis.cluster.maxRedirects=3

redis.cluster.host1=192.168.1.30
redis.cluster.port1=7000

redis.cluster.host2=192.168.1.30
redis.cluster.port2=7001

redis.cluster.host3=192.168.1.30
redis.cluster.port3=7002

redis.cluster.host4=192.168.1.224
redis.cluster.port4=7003

redis.cluster.host5=192.168.1.224
redis.cluster.port5=7004

redis.cluster.host6=192.168.1.224
redis.cluster.port6=7005

#JedisPoolConfig
redis.cluster.jedisPoolConfig.maxTotal=1024
redis.cluster.jedisPoolConfig.maxIdle=20
redis.cluster.jedisPoolConfig.maxWaitMillis=100000
redis.cluster.jedisPoolConfig.testOnBorrow=true

#JedisConnectionFactory
redis.cluster.jedisConnectionFactory.password=admin复制代码

(3)修改web.xml:

在web.xml中添加如下filter:cookie

<!-- Spring Session配置 -->
    <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>复制代码

注:须要将这个filter放在第一位,其余的如编码、shiro等filter须要放在这以后

到此,Spring Session和Spring Data Redis就整合到项目中了

(4)测试:

运行项目后,能够发现生成了一个名为“SESSION”的cookie。接着在咱们登陆以后,能够经过其cookie值在redis上取得保存的对应的session对象。以下图所示:


从上图能够发现,登陆以后的用户对象已经保存到redis集群中了。接着还能够测试将一样的项目发布到其余端口的tomcat上,在同一浏览器上访问须要登陆认证以后才能访问的页面,看看是否可以直接访问。若是可以直接访问而不是重定向到登陆页面,则说明已经达到session共享的效果了

参考:

相关文章
相关标签/搜索