在Web项目开发中,会话管理是一个很重要的部分,用于存储与用户相关的数据。通常是由符合session规范的容器来负责存储管理,也就是一旦容器关闭,重启会导致会话失效。因此打造一个高可用性的系统,必须将session管理从容器中独立出来。而这实现方案有很多种,下面简单介绍下:
第一种是使用容器扩展来实现,大家比较容易接受的是通过容器插件来实现,比如基于Tomcat的tomcat-redis-session-manager,基于Jetty的jetty-session-redis等等。好处是对项目来说是透明的,无需改动代码。不过前者目前还不支持Tomcat 8,或者说不太完善。个人觉得由于过于依赖容器,一旦容器升级或者更换意味着又得从新来过。并且代码不在项目中,对开发者来说维护也是个问题。
第二种是自己写一套会话管理的工具类,包括Session管理和Cookie管理,在需要使用会话的时候都从自己的工具类中获取,而工具类后端存储可以放到Redis中。很显然这个方案灵活性最大,但开发需要一些额外的时间。并且系统中存在两套Session方案,很容易弄错而导致取不到数据。
第三种是使用框架的会话管理工具,也就是本文要说的spring-session,可以理解是替换了Servlet那一套会话管理,既不依赖容器,又不需要改动代码,并且是用了spring-data-redis那一套连接池,可以说是最完美的解决方案。当然,前提是项目要使用Spring Framework才行。
这里简单记录下整合的过程:
如果项目之前没有整合过spring-data-redis的话,这一步需要先做,在maven中添加这两个依赖:
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.5.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> <version>1.0.2.RELEASE</version> </dependency>
再在applicationContext.xml中添加以下bean,用于定义redis的连接池和初始化redis模版操作类,自行替换其中的相关变量。
<!-- redis --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> </bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.pass}" /> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="jedisPoolConfig" /> <property name="usePool" value="true" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> </bean> <!-- 将session放入redis --> <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> <property name="maxInactiveIntervalInSeconds" value="1800" /> </bean>
这里前面几个bean都是操作redis时候使用的,最后一个bean才是spring-session需要用到的,其中的id可以不写或者保持不变,这也是一个约定优先配置的体现。这个bean中又会自动产生多个bean,用于相关操作,极大的简化了我们的配置项。其中有个比较重要的是springSessionRepositoryFilter,它将在下面的代理filter中被调用到。maxInactiveIntervalInSeconds表示超时时间,默认是1800秒。写上述配置的时候我个人习惯采用xml来定义,官方文档中有采用注解来声明一个配置类。
然后是在web.xml中添加一个session代理filter,通过这个filter来包装Servlet的getSession()。需要注意的是这个filter需要放在所有filter链最前面。
<!-- delegatingFilterProxy --> <filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
这样便配置完毕了,需要注意的是,spring-session要求Redis Server版本不低于2.8。
验证:使用redis-cli就可以查看到session key了,且浏览器Cookie中的jsessionid已经替换为session。
127.0.0.1:6379> KEYS * 1) "spring:session:expirations:1440922740000" 2) "spring:session:sessions:35b48cb4-62f8-440c-afac-9c7e3cfe98d3"
本文链接地址:https://dorole.com/1422/
按照配置遇到如下报错,还未解决.
严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Method ‘propertySourcesPlaceholderConfigurer’ must not be private, final or static; change the method’s modifiers to continue
Offending resource: class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
at org.springframework.context.annotation.ConfigurationClassMethod.validate(ConfigurationClassMethod.java:61)
at org.springframework.context.annotation.ConfigurationClass.validate(ConfigurationClass.java:139)
at org.springframework.context.annotation.ConfigurationClassParser.validate(ConfigurationClassParser.java:167)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:198)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:142)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:599)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:407)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5099)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5615)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1571)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1561)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
我能说查了一天发现是配置文件名称写错了吗
context-param 中contextConfigLocation需要引入 spring-mvc.xml的路径
用spring-session的时候如果再使用 session范围的bean 会爆不能序列化异常 遇到过吗?
没试过
我这里也出现了No bean named ‘springSessionRepositoryFilter’ is defined 可以发一个demo给我邮箱吗?万分感谢!!
我遇到后No bean named ‘springSessionRepositoryFilter’搞定了,可以参考如下链接文章
http://blog.csdn.net/tgj1202/article/details/51995853
我參考了文章, 但還是無法解決呢
請問一下你是怎麼解決的呢? 謝謝你
我最後放棄使用 xml configuration 改用 java configuration, 亦就是說使用 annotation 的方式把 bean 注入, 已可正常使用
JDK1.7
Spring3.2.14
你的问题解决了吗,现在我也在弄这个。想找你交流下。QQ227489552
我也碰到了这个问题。错误如下:
严重: Exception starting filter springSessionRepositoryFilter
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘springSessionRepositoryFilter’ is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1057)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:260)
at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:105)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4658)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5277)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
六月 21, 2016 1:56:39 下午 org.apache.catalina.core.StandardContext startInternal
严重: One or more Filters failed to start. Full details will be found in the appropriate container log file
六月 21, 2016 1:56:39 下午 org.apache.catalina.core.StandardContext startInternal
严重: Context [/springsession] startup failed due to previous errors
这个问题有解决办法吗,我也碰到了
我是少了一个 在applicationContext.xml
也不知道为什么,这个设置会影响
context:annotation-config
我也是报这个错误,郁闷:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘springSessionRepositoryFilter’ is defined
配置如下:
web.xml
contextConfigLocation
/WEB-INF/applicationContext.xml
springSessionRepositoryFilter
org.springframework.web.filter.DelegatingFilterProxy
springSessionRepositoryFilter
/*
org.springframework.web.context.ContextLoaderListener
applicationContext.xml:
想问一下这个版本spring
一定要用4.0以上的版本吗
不用
java.lang.VerifyError: (class: org/springframework/data/redis/connection/jedis/JedisConnectionFactory, method: createRedisSentinelPool signature: (Lorg/springframework/data/redis/connection/RedisSentinelConfiguration;)Lredis/clients/util/Pool;) Incompatible argument to function
我这个配置的是
spring3.1.3 然后
redis 2.1
spring-session 1.0.2;
spring-data-redis 1.5.2.RELEASE
jedis版本过低?我这是2.7.3的。
我换了一下 请问你的spring-data-redis是什么版本呢
上面有 1.5.2,注意redis-server和jedis
redis-server 是2.8.9的
按照你的配置后,我一启动 就报No bean named ‘springSessionRepositoryFilter’ is defined 全部都按照您的配置配置号的,也检查了好几遍。。还是希望你可以给我看看您的demo
applicationContext.xml 中有没配置redisHttpSessionConfiguration ?
我也遇到同样的问题,严重: Exception starting filter springSessionRepositoryFilter
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘springSessionRepositoryFilter’ is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:387)
确认所有配置都没问题吗,还有名称。我这里是ok的,已经在生产环境跑了很久了。我这里Spring 版本是3.2的。调试下看有什么线索。
我这边测试也没有问题。
我取用sprint3.2.14 也是一樣的報錯
RedisHttpSessionConfiguration看log是也有注入這個bean了 但還是沒取到filter bean..
不知道該怎麼解決 現在挺苦惱的
我的也是这个问题啊,不过我的是在集群的那种情况下出现的
大哥我的问题应该和你一样,我也是在集群环境下遇到的,我为了测试,配置了一主一从一哨兵,通过日志文件也能看出来确实都启动连接了
信息: Trying to find master from available Sentinels…
2016-8-18 10:01:33 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 127.0.0.1:6379, starting Sentinel listeners…
2016-8-18 10:01:33 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 127.0.0.1:6379
但是马上抛出异常
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘springSessionRepositoryFilter’ defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.session.SessionRepository]: : No qualifying bean of type [org.springframework.session.SessionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.session.SessionRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
求问您解决这个问题了吗