内容简介:如果你正在使用Java开发Web应用,想必你对HttpSession非常熟悉,但我们知道HpptSession默认使用内存来管理Session,如果将应用横向扩展将会出现Session共享问题。Spring Session提供了一套创建和管理Servlet HttpSession的方案,以此来解决Session共享的问题,更为重要的是在Spring Boot中使用它极其简单。HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。如果我们将Web应用横向扩展
前言
如果你正在使用 Java 开发Web应用,想必你对HttpSession非常熟悉,但我们知道HpptSession默认使用内存来管理Session,如果将应用横向扩展将会出现Session共享问题。Spring Session提供了一套创建和管理Servlet HttpSession的方案,以此来解决Session共享的问题,更为重要的是在Spring Boot中使用它极其简单。
Session共享的问题
HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。如果我们将Web应用横向扩展搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户的Http请求将有可能被负载分发到两个不同的实例中去,如何保证不同实例间Session共享成为一个不得不解决的问题。
最简单的解决方法就是把Session数据保存到内存以外的一个统一的地方,例如Memcached/Redis中。那么问题又来了,如何替换掉Servlet容器创建和管理HttpSession的实现呢?
- 利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。不过这种方式有个缺点,就是需要耦合Tomcat/Jetty等Servlet容器的代码。这方面其实早就有开源项目了,例如memcached-session-manager,以及tomcat-redis-session-manager。暂时都只支持Tomcat6/Tomcat7。
- 配置Nginx的负载均衡算法为ip_hash,这样每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的Session共享问题
- 如果你使用Shiro管理Session,可以用 Redis 来实现Shiro 的SessionDao接口,这样Session便归Redis保管。
- 设计一个Filter,利用HttpServletRequestWrapper,实现自己的 getSession()方法,接管创建和管理Session数据的工作。Spring-Session就是通过这样的思路实现的。
在Spring Boot中 集成 Spring Session
Spring Session 支持使用Redis、Mongo、JDBC、Hazelcast来存储Session,这里以Redis为例。
- 引入Maven依赖(本示例使用
dependencyManagement
,如果你没有使用它请添加<version>
标签)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> </dependency>
- 配置你的Spring Application,将你的
application.properties
加入以下配置。
spring.session.store-type=redis
仅此两步,便集成完毕,整个过程完全无痛、无感~
<small>注意:如果你的Redis服务器不是使用本地默认配置( localhost:6379
),需要配置你的Redis,如何配置?看这里。</small>
我们来验证一下~
Debug,Http Session
果然, Http Session
已被 Spring Session
进行包装,我们可以依旧使用 Http Session
的API来进行编程。
Cookies
Cookies 也正常创建,Key为SESSION。
127.0.0.1:6379> keys * 1) "spring:session:sessions:083706a8-b2d8-480c-8b88-eafc798e7269" 2) "spring:session:sessions:expires:083706a8-b2d8-480c-8b88-eafc798e7269" 3) "spring:session:expirations:1490263320000"
使用redis-cli查看,发现Redis中也已保存相关数据。
来源: https://www.jianshu.com/p/e4191997da56
————-
3、Spring Session-使用Hazelcast的HttpSession
2017年09月19日 19:08:03 RonTech 阅读数:957
4.4. 使用Hazelcast的HttpSession
在使用HttpSession的任何功能之前通过添加一个Servlet过滤器,就可以启用Spring Session。
本节主要介绍基于Java配置如何使用Hazelcast支持HttpSession。
Hazelcast Spring样例提供了一个可执行的样例,这个样例提供了如何基于Java配置整合Spring Session和HttpSession。你可以阅读以下的一些基础步骤,但是当您与自己的应用程序整合时,推荐遵循详细的Hazelcast Spring参考指南。
4.4.1. Spring 配置
添加完成必要的依赖之后,我们需要创建我们自己的Spring配置,Spring配置负责创建一个Servlet过滤器,这个过滤器通过一个使用Spring Session支持的实现去替换HttpSession。添加如下的Spring配置:
@EnableHazelcastHttpSession @Configuration public class HazelcastHttpSessionConfig { @Bean public HazelcastInstance hazelcastInstance() { MapAttributeConfig attributeConfig = new MapAttributeConfig() .setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) .setExtractor(PrincipalNameExtractor.class.getName()); Config config = new Config(); config.getMapConfig("spring:session:sessions") .addMapAttributeConfig(attributeConfig) .addMapIndexConfig(new MapIndexConfig( HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); return Hazelcast.newHazelcastInstance(config); } }
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- @EnableHazelcastHttpSession 注解创建了一个实现了Filter的名为springSessionRepositoryFilter 的Bean(过滤器),这个过滤器负责使用Spring Session支持的一个实现去替换HttpSession,这个实例中Spring Session由Hazelcast支持;
- 为了支持按principal name index检索会话,需要注册适当的ValueExtractor。Spring Session为此提供了PrincipalNameExtractor。
- 创建一个HazelcastInstance链接Spring Session和Hazelcast,默认情况下,一个嵌入的Hazelcast 默认实例会被启动并被应用所链接。关于更多配置Hazelcast的信息,可以参考 参考文档
4.4.2. Servlet容器初始化
Spring配置文件创建了一个实现了Filter的名为springSessionRepositoryFilter 的Bean,springSessionRepositoryFilter负责使用一个支持Spring Session的个性化实现替换HttpSession。
为了让我们的Filter发挥它的魔力,Spring需要加载我们的SessionConfig 类。由于我们的应用程序已经使用SecurityInitializer类加载了Spring配置,所以我们可以简单地添加我们的SessionConfig类。
src/main/java/sample/SecurityInitializer.java public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { public SecurityInitializer() { super(SecurityConfig.class, SessionConfig.class); } }
最后我们需要确保Servlet容器(如Tomcat)的每个请求都使用了springSessionRepositoryFilter,非常重要的一点就是Spring Session的springSessionRepositoryFilter 必须在Spring Security’s springSecurityFilterChain之前被调用。这样就能够确保Spring Security使用的HttpSession也被Spring Session支持。幸运的是,Spring Session提供了一个很有效的名为AbstractHttpSessionApplicationInitializer的类,这个类会让实现以上的这些功能变得非常的容易。请看下面的例子:
src/main/java/sample/Initializer.java public class Initializer extends AbstractHttpSessionApplicationInitializer { }
我们自己的类(Initializer )的命名我们并不关心,最重要的是要继承AbstractHttpSessionApplicationInitializer。
继承AbstractHttpSessionApplicationInitializer 之后我们就能确保名为springSessionRepositoryFilter 的Spring Bean被注册到Servlet容器中,并且对于每一个请求的处理他都会处在Spring Security’s springSecurityFilterChain过滤器链中的所有过滤器之前。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 如何解决分布式集群会话?
- java – Spring会话数据Redis – 从Redis Store获取有效会话,当前用户
- google-app-engine – GAE webapp2会话:创建和检查会话的正确过程
- 图解 Session(会话)
- 内网会话劫持
- Tomcat集群之会话保持
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。