美文网首页
Spring Session来做多机会话共享一

Spring Session来做多机会话共享一

作者: 螃蟹和骆驼先生Yvan | 来源:发表于2018-08-17 16:42 被阅读173次

    1.前言

    最近技术总监在群里问个问题,我比较在意就是如何把spring session做成多机会话共享(集群)
    主要遇到情况例如:
    一个用户登录成功之后,然后去访问一个查询接口突然就宕机了,怎么办,就算你做了负载均衡但是你当前一个会话丢失了,用户还需要重新登录,很影响用户的体验。
    这里就要说到我们技术总监说的问题,Spring Session作为多机会话共享的问题:
    先解释一下Session的本质是什么?
    1.设置一个生命周期
    2.浏览器登录时根据生成的token保存session
    3.在过期前同一个浏览器共享那个session里面所有的内容
    通俗易懂的解释就是一次会话
    我们在看看SessionID的本质?
    通俗易懂的解释,确定用户是在同一会话,就是确定这个用户。

    这里在正式解释一下为何Spring Session作为多机会话共享可以解决用户重新登录问题:
    Session存储的在内存当中,所以一但服务器挂了,内存里面东西就会丢失,但是通过Spring Session可以通过一个配置类创建一个过滤器,这个过滤器支持Spring Session代替HttpSession发挥作用,这样就可以把session存放在redis缓存当中,不至于服务器挂了,你的Session会话就丢失,也可以实现多台服务器共享这个会话,只要你的那些服务器用的是同一redis。

    2.依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>SpringSession</groupId>
        <artifactId>SpringSession</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.3.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- spring session -->
            <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session</artifactId>
                <version>1.3.0.RELEASE</version>
            </dependency>
            <!-- redis -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-redis</artifactId>
            </dependency>
    
    
            <!-- servlet 依赖. -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
            </dependency>
            <!-- tomcat 的支持.-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <scope>provided</scope>
            </dependency>
        </dependencies>
        <build>
            <finalName>SpringSession</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin </artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    3.这个配置类可以创建一个过滤器,这个过滤器支持Spring Session代替HttpSession发挥作用。

    import org.springframework.context.annotation.Bean;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
    
    @EnableRedisHttpSession
    public class HttpSessionConfig {
        @Bean
        public JedisConnectionFactory connectionFactory() {
            return new JedisConnectionFactory();
        }
    }
    

    4.Controller层:

    import java.util.UUID;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @Controller
    public class UserController {
        @RequestMapping(value="/main", method=RequestMethod.GET)
        public String main(HttpServletRequest request) {
            HttpSession session = request.getSession();
            String sessionId = (String) session.getAttribute("sessionId");
            if (null != sessionId) { // sessionId不为空
                System.out.println("main sessionId:" + sessionId);
                return "main";
            } else { // sessionId为空
                return "redirect:/login";
            }
        }
    
        @RequestMapping(value="/login", method=RequestMethod.GET)
        public String login() {
            return "login";
        }
    
        @RequestMapping(value="/doLogin", method=RequestMethod.GET)
        public String doLogin(HttpServletRequest request) {
            System.out.println("我在这里登陆");
            HttpSession session = request.getSession();
            String sessionId = UUID.randomUUID().toString();
            session.setAttribute("sessionId", sessionId);
            System.out.println("login sessionId:" + sessionId);
            return "redirect:/main";
        }
    
    }
    

    4.在 src/main 下面创建 webapp/WEB-INF/jsp 目录用来存放我们的jsp页面:login.jsp,main.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
             pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    helloJsp
    <hr>
    ${hello}
    
    </body>
    </html>
    
    <%@ page language="java" contentType="text/html; charset=UTF-8"
             pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    this is main
    <hr>
    ${hello}
    
    </body>
    </html>
    

    5.application.properties配置类

    # 页面默认前缀目录
    spring.mvc.view.prefix=/WEB-INF/jsp/
    # 响应页面默认后缀
    spring.mvc.view.suffix=.jsp
    # 自定义属性,可以在Controller中读取
    application.hello=Hello Angel From application
    
    # REDIS (RedisProperties)
    spring.redis.database=0
    spring.redis.host=localhost
    spring.redis.port=6379
    spring.redis.password=
    # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.jedis.pool.max-active=8  
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.jedis.pool.max-wait=-1  
    # 连接池中的最大空闲连接
    spring.redis.jedis.pool.max-idle=8  
    # 连接池中的最小空闲连接
    spring.redis.jedis.pool.min-idle=0
    spring.redis.jedis.timeout=0
    

    6.测试

    你访问http://localhost:8080/main
    然后去redis查询如图:

    未访问页面时候,Session还未存储到redis里面
    访问的页面,存储到redis里面
    这里就成功把Session存储到redis里面,其实这里只是Spring Session来做多机会话共享一,后期我会把服务器部署多机会话写出来,请关注我。

    指导qq:179061434

    参考demo:链接: https://pan.baidu.com/s/1T-5KIES7pTmE3xViY-DeIw 密码: 874g

    相关文章

      网友评论

          本文标题:Spring Session来做多机会话共享一

          本文链接:https://www.haomeiwen.com/subject/wkctiftx.html