分布式session不共享不同步的问题:
常规的,session:
我们可以理解session(办理的各种业务等)就是 保存在服务器内存中的一块数据(保存在map中),访问某一个网站,则客户端保存一个该网站发给其的cookie(银行卡)。
不同域名下,session无法共享:
如何解决session的无法共享问题?
1.session复制(同步)方案
缺点: 加入100个服务器,要完成session的共享,则需要各自都有100g的内存,来保存所有服务器的session数据,在大型服务项目中是不适用的。
2.客户端存储session
3.hash一致性
4.Session共享问题解决——统一存储
将session存储在中间件中,例如 DB/Redis
通过springSession来解决不同域的session共享问题。
当在auth.gulimall.com下边登录之后,session保存用户名,然后用户名可以在不同域下都可以使用,就实现了session的共享问题。
通俗来讲,例如: 在 auth.gulimall.com下的session,在 gulimall.com下也能用,在order.gulimall.com下也能用。
使用:
1.导入spring - session - data - redis的依赖
2.开启redis作为session的存储
3.当登录完成之后,就会保存一个vo数据,该数据就是要保存的session对象,如果要将该数据保存到redis中,就需要先对该vo进行序列化从而保存到redis里边。
如下实现序列化:
理解:把需要共享session的服务 整合springSession依赖,然后将这些session保存到redis中,其它的服务都可以在redis里边把session信息拿出来并使用。例子就是登录服务的session保存到redis中,然后其它服务,如商品服务和主页服务都可以拿到,并一直保存登录状态。
问题: auth服务的session,无法实现子域的共享---TODO
要实现session的子域共享,就是把cookie的域名给放大到了父域中:
实现域名的放大效果,进行自定义的session配置:1.cookieSerializer,进行session的域名和cookie名的修改 2.实现session的json格式序列化机制,使用了Jackson方法序列化 3.将session的 config配置,因为每一个服务都需要,因此抽取出来放到common项目下。
进行了相关的自定义配置之后,需要在html页面也进行相关的修改:如果未登录,则返回空串,反之返回登录名称。
总结:
每一个微服务都要配置整合springSession(相关session保存在redis中——当然要在项目中进行redis和springSession的配置, 哪一个微服务需要这样的“登录Session”,就进行redis和springSession的配置,然后auth服务的“登录session”数据就可以保存在了redis中。
将“登录session”保存在redis之前,要进行自定义session的配置:1.设置cookie域名(将cookie域名放大到父域——实现session的子域共享)2.指定json序列化器对session进行序列化,便于微服务对于redis中session数据的存取。
至此,完成了session的子域共享问题。
springSession的核心原理(通过装饰者模式实现的):主要实现该功能的就是SessionRepositoryFilter,主要的核心逻辑如下:
通过装饰者模式改变了默认的Filter,变成: SessionRepositoryFilter。
当前端来一个请求,则会对该请求进行包装成一个 wrappedRequest的对象,然后调取wrappedRequest对象的.getSession()对session进行增删改查,所有对session的增删改查都是在redis中进行的。
如何保存session的呢? 是通过SessionRepository接口进行保存的(相当于Dao),通过接口的不同实现——可以使用 map保存session(则保存在redis中)——可以使用redis保存在redis中 ——如果引入JDBC相关的场景,还可以使用数据库保存session...
具体的:
1.完成springSession的依赖整合,在服务中使用@EnableRedisHttpSession注解,且该注解源码中添加了组件:RedisHttpSessionConfiguration ,里边添加了RedisOperationSessionRepository组件,是进行redis操作session的,在redis中进行session的增删改查。
RedisOperationSessionRepository中包含的方法有:
2.RedisHttpSessionConfiguration 就是 SpringHttpSessionConfiguration,添加了 SessionRepositoryFilter组件,是session的存储过滤器,而该Filter就是spring里边默认的Filter,每一个请求过来都必须经过该Filter。
3. 2中的SessionReposityFilter中只包含一个有参构造器,且传入的是一个 SessionRepository,就是存储session的“仓库”,即 RedisOperationSessionRepository。
因此当Filter创建的时候,就自动从容器中获取到了SessionReposity,即 RedisOperationSessionRepository。
4. 通过SessionRepositoryFilter重写了Spring中原生的Filter方法,核心逻辑如下:
4.1 SessionRepositoryFilter中的 doFilterInternal()方法对原始的Http原始请求对象和响应对象都进行了包装,分别包装成: SessionRepositoryRequestWrapper和SessionRepositoryResponseWrapper类型的对象wrappedRequest和wrappedResponse,并使用包装后的对象进行后序业务逻辑。
对于原生的http请求中的session进行获取,是使用request.session()获取到, 由于 doFilterInternal()对原生的Http中的session进行了包装,因此使用包装后的对象 wrappedRequest.getSession()获取到包装后的session:
4.1.1.该session是从SessionRepository中获取到的。
4.1.2.getSession()方法是重写了spring中的filter。
4.1.3 getSession()方法执行对session的获取。