码迷,mamicode.com
首页 > 编程语言 > 详细

Redis实战和核心原理详解(5)使用Spring Session和Redis解决分布式Session跨域共享问题

时间:2019-10-18 14:04:35      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:use   frame   ash   框架   event   clust   void   context   时间   


Redis实战和核心原理详解(6)使用Spring Session和Redis解决分布式Session跨域共享问题

 

前言

对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash、轮训、根据权重、随机等。不管对于哪一种负载均衡算法,由于Nginx对不同的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不同的容器里,因此会出现session不同步或者丢失的问题。

实际上实现Session共享的方案很多,其中一种常用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis)中。

这一篇文章中已经学习了一下,如何使用 tomcat-redis-session-manager 开源项目解决分布式session跨域的问题,他的主要思想是利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。tomcat-redis-session-manager重写了Tomcat的org.apache.catalina.session.ManagerBase里边的具体写的操作, 将tomcat的session存储位置指向了Redis:

技术图片

RedisSessionManager继承了org.apache.catalina.session.ManagerBase并重写了add、findSession、createEmptySession、remove等方法,并将对session的增删改查操作指向了对Redis数据存储的操作。

不过使用过***tomcat-redis-session-manager*** 的都应该知道,配置相对还是有一点繁琐的,需要人为的去修改Tomcat的配置,需要耦合Tomcat等Servlet容器的代码,并且对于分布式Redis集群的管理并不是很好,与之相对的个人认为比较好的一个框架Spring Session可以真正对用户透明的去管理分布式Session。

Spring Session不依赖于Servlet容器,而是Web应用代码层面的实现,直接在已有项目基础上加入spring Session框架来实现Session统一存储在Redis中。如果你的Web应用是基于Spring框架开发的,只需要对现有项目进行少量配置,即可将一个单机版的Web应用改为一个分布式应用,由于不基于Servlet容器,所以可以随意将项目移植到其他容器。

Spring Session使用

官方地址:http://projects.spring.io/spring-session/

官方文档地址:http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/

Spring Session提供了一套创建和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能,默认采用外置的Redis来存储Session数据,以此来解决Session共享的问题。

一、特性

Spring Session提供以下特性:

  1. API和用于管理用户会话的实现;
  2. HttpSession - 允许以应用程序容器(即Tomcat)中性的方式替换HttpSession;
    1. Clustered Sessions - Spring Session让支持集群会话变得不那么繁琐,并且不和应用程序容器金习性绑定到。
    2. Multiple Browser Sessions - Spring会话支持在单个浏览器实例中管理多个用户的会话。
    3. RESTful APIs - Spring Session允许在headers 中提供会话ID以使用RESTful API。

二、基于XML配置方式的Spring Session案例实现

基于SSM框架的一个小案例。

技术图片

项目展示:

技术图片

(1)基本环境需求

进行使用Spring Session的话,首先的是已经安装好的有一个 Redis服务器!

(2)添加项目依赖(最基本的依赖使用)

 <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>1.3.0.RELEASE</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>biz.paluch.redis</groupId>
            <artifactId>lettuce</artifactId>
            <version>3.5.0.Final</version>
        </dependency>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

(3)添加Spring配置文件

添加了必要的依赖之后,我们需要创建相应的Spring配置。Spring配置是要创建一个Servlet过滤器,它用Spring Session支持的HttpSession实现来替换容器本身HttpSession实现。这一步也是Spring Session的核心。

<context:annotation-config/>

<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
 
  • 1
  • 2
  • 3
  • 4
  • 5

上述代码注释:

技术图片

LettuceConnectionFactory实例是配置Redis的ConnectionFactory。

注意:

<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
 
  • 1

查看源代码可以看到,默认的Redis链接配置为:

技术图片

因此,如果有自己的Redis配置,请修改,例如下边的配置:

<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
     <property name="hostName" value="192.168.1.149"/>
     <property name="port" value="6379"/>
     <property name="password" value="123456"/>
</bean>
 
  • 1
  • 2
  • 3
  • 4
  • 5

(5)关于Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer’错误的处理:

添加如下配置让Spring Session不再执行config命令

<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
 
  • 1

如果不添加的话,会报如下错误:

Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer‘ defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]:
Invocation of init method failed; nested exception is java.lang.IllegalStateException: Unable to configure Redis to keyspace notifications.
See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent
Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR unknown command config
 
  • 1
  • 2
  • 3
  • 4

(5)在web.xml中添加DelegatingFilterProxy

<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>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

DelegatingFilterProxy将通过springSessionRepositoryFilter的名称查找Bean并将其转换为过滤器。对于调用DelegatingFilterProxy的每个请求,也将调用springSessionRepositoryFilter。

(6)Spring MVC controller代码用于测试:

@Controller
@RequestMapping(value = "/spring/session", produces = {ConstString.APP_JSON_UTF_8})
public class SpringSessionDemoController {

    @RequestMapping(value = "/setSession.do", method = RequestMethod.GET)
    public void setSession(HttpServletRequest request, HttpServletResponse response) {
        String name = request.getParameter("name");
        String value = request.getParameter("value");
        request.getSession().setAttribute(name, value);
    }

    @RequestMapping(value = "/getSession.do", method = RequestMethod.GET)
    public void getInterestPro(HttpServletRequest request, HttpServletResponse response) {
        String name = request.getParameter("name");
        System.out.println("------" + request.getSession().getAttribute(name));
    }

    @RequestMapping(value = "/removeSession.do", method = RequestMethod.GET)
    public void removeSession(HttpServletRequest request, HttpServletResponse response) {
        String name = request.getParameter("name");
        request.getSession().removeAttribute(name);
    }
}
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

技术图片

(7)测试

使用工具查看Redis内容:

技术图片

可以发现已经有值了!并且有expirations,可以看到箭头指向的位置,是失效的时间记录值!

(8)到此,Spring Session的使用已经完成!

总结

对于分布式环境Session跨域共享的问题,不管是使用开源的框架还是使用自己开发的框架,都需要明白的一个问题是:在Tomcat容器中创建Session是一个很耗费内存的事情。因此,我们在自己写类似框架的时候,我们一定要注意的是,并不是Tomcat为我们创建好了Session之后,我们首先获取Session然后再上传到Redis等进行存储,而是直接有我们自己创建Session,这一点是至关重要的!

 

Redis实战和核心原理详解(5)使用Spring Session和Redis解决分布式Session跨域共享问题

标签:use   frame   ash   框架   event   clust   void   context   时间   

原文地址:https://www.cnblogs.com/ko88/p/11697851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!