SpringCloud 学习-SpringSession介绍,使用,整合项目解决Session常规问题

SpringCloud 学习-SpringSession介绍,使用,整合项目解决Session常规问题

1. SpringCloud为什么要用SpringSession? HttpSession不行吗?

HttpSession的问题:

  • 不同服务,session不能共享的问题:不能跨不同域名之间共享session的数据,因为不同域名之间,cookie中的sessionID是不共享的.
  • 同一服务,复制在多台服务器,session不同步的问题:session的数据存在服务器中,而分布式微服务环境下,同一服务模块可能存在多台服务器,服务器之间的session也无法共享

1.1 session 不同步问题的解决方法

方法一:session复制 (适合小型系统)

​ 在同一个服务的不同服务器之间,同步session的数据.

  • 优点:
    • web-server(Tomcat) 原生支持,只需要修改配置文件
  • 缺点:
    • session同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力
    • 任意一台web-server保存的数据都是所有web-server的session总和,数据冗余
    • 大量分布式的集群情况下,由于所有的web-server都全量保存数据,所以此方法可取.

方法二:利用ip_hash一致性 (可使用)

​ 在nginx负载均衡时,利用ip地址的hash一致性,所有该用户的请求都控制的发往固定的服务器.

  • 优点:
    • 只需要修改nginx的配置,不需要修改应用代码
    • 负载均衡,只要hash属性的值分布式均衡的,多台web-server的负载也是均衡的
    • 可以支持web-server的水平拓展(不受内存限制,区别于session复制方法)
  • 缺点:
    • session还是存在web-server中,所有web-server重启可能导致部分session丢失,影响业务

方法三:统一存储(分布式微服务情况下推荐使用)

​ 无论哪一个web-server,session都不存在服务器中,而是统一存储在数据库或者redis类缓存中.

  • 优点:
    • 没有安全隐患
    • 可以水平扩展
    • session不会丢失
  • 缺点:
    • 增加了一次网络调用.
    • 需要修改应用代码,如果将所有的getSession方法替换为从redis查数据的方式,redis获取数据会比内存中慢很多

注意:以上的缺点,可以使用SpringSession完美解决


1.2 session不能跨域共享的问题

解决方法:子域之间共享JSESSIONID

​ 在存储session时,会将JSESSIONID保存在浏览器,并指定域名范围,因此在指定域名范围时,使用父域名,则该JSESSIONID在所有父子域名中生效.

注意:可以使用SrpingSession完成修改有效域名范围

2. SpringBoot 整合SpringSession

导入依赖:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-bom</artifactId>
      <version>Corn-SR2</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
  </dependency>
</dependencies>

修改配置文件

server:
  port: 20000
  servlet:
    session:
      timeout: 30m  #session过期时间 默认30m
spring:
  redis:  #配置redis连接信息
    host: 192.168.231.1
    port: 6379
  session:
    store-type: redis	#指定使用redis 存储session

添加@EnableRedisHttpSession 开启SpringSession

@EnableRedisHttpSession
public class Application {
    
    
   public static void main(String[] args) {
    
    
      SpringApplication.run(Application.class, args);
   }

}

将需要存放在session中的对象添加序列化接口Serializable

SpringSession需要将存入session的对象序列化后存放在redis中,默认采用字节码序列化,可添加配置类修改为JSON形式

public class Member implements Serializable{
    
    
    private Long id;
}

SpringSession的配置

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

@Configuration
public class GulimailSessionConfig {
    
    
    //配置JSESSIONID的作用域
    @Bean
    public CookieSerializer cookieSerializer(){
    
    
        DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
        defaultCookieSerializer.setCookieName("GULIMAILSESSION");
        defaultCookieSerializer.setDomainName(".gulimail.com"); //将JSESSIONID作用域提高到父域名
        return defaultCookieSerializer;
    }

    //配置序列化类型为JSON
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer(){
    
    
        return new GenericFastJsonRedisSerializer();
    }
    
}

使用session保存数据

使用方法域普通session相同:

session.setAttribute("loginUser",member);

添加完成后,redis会创建出缓存数据和过期时间

在这里插入图片描述

使用session取数据:

<a href="http://auth.gulimail.com/login.html">你好,请登录:[[${session.loginUser.nickname}]]</a>
  • 若跨服务模块进行session使用,需要在取数据的模块的同一路径下存放相同的实体类Member,否则会报序列化找不到类的错误.

猜你喜欢

转载自blog.csdn.net/weixin_44634197/article/details/108518396