美文网首页
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