基于Spring-Session如何实现会话共享
更新:HHH   时间:2023-1-7


今天就跟大家聊聊有关基于Spring-Session如何实现会话共享,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

前段时间,在对项目权限框架调整的时候(SpringSecurity改成Shiro),集成了SpringSession小插件。

    由于现今本项目某些特性,暂时无法进行分布式部署,所以对SpringSession并没有进行深入测试以及生产上部署应用,这里只是记录整合的过程以及一些心得。

    网上也看到一些同学说SpringSession存在一些坑,比如无法实现跨域Session共享,然后通过修改其Cookie生产策略可以进行解决等,因此在生产使用之前,还需进行充分的测试。

学习@Configuration、@Bean两个Spring注解:

Spring中为了减少xml中配置,引入了@Configuration和@Bean注解类。@Configuration注解的类,等价于XML中配置beans,表明这个类是beans定义的源;@Bean注解的方法等价于XML中配置的bean,该方法创建出的实例由Ioc容器管理。

    SpringSession核心的配置类为SpringHttpSessionConfiguration(框架也默认提供了Redis、Mongo、Jdbc等实现,本项目使用RedisHttpSessionConfiguration)。RedisHttpSessionConfiguration类中最重要的两个操作就是创建springSessionRepositoryFilter以及sessionRedisTemplate。在创建sessionRedisTemplate时框架会依赖解析RedisConnectionFactory,所以在Spring配置中我们需要定义RedisConnectionFactory;springSessionRepositoryFilter是SpringSession的核心,也是web.xml中Filter代理,整个Session的获取以及提交都在其里实现。

以下是整个配置的过程:

1、applicationContext-session.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:util="http://www.springframework.org/schema/util"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd 
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd 
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd 
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd 
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd" default-lazy-init="true">
	
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${redis.pool.maxTotal}" />
		<property name="maxIdle" value="${redis.pool.maxIdle}" />
		<property name="minIdle" value="${redis.pool.minIdle}" />
		<property name="blockWhenExhausted" value="${redis.pool.blockWhenExhausted}"></property>
		<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
		<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
		<property name="testOnReturn" value="${redis.pool.testOnReturn}" />
		<property name="testWhileIdle" value="${redis.pool.testWhileIdle}" />
		<property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}" />
		<property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}" />
		<property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}" />
	</bean>
	
	<!-- @Important -->
	<!-- Autowired By Type Of org.springframework.data.redis.connection.RedisConnectionFactory -->
	<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.password}" />
		<property name="database" value="${redis.database}" />
		<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>
	
	<bean id="httpSessionMonitorListener" class="com.wuzb.pw.common.session.HttpSessionMonitorListener"></bean>

	<!-- @Important -->
	<!-- Cookie strategy is the framework default strategy,But exist cross-domain problem -->
	<!-- Reason: org.springframework.session.web.http.DefaultCookieSerializer.getCookiePath(HttpServletRequest) -->
	<bean id="cookieHttpSessionStrategy" class="org.springframework.session.web.http.CookieHttpSessionStrategy"></bean>

	<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
		<property name="maxInactiveIntervalInSeconds" value="1800" />
		<property name="httpSessionStrategy" ref="cookieHttpSessionStrategy"/>
		<property name="httpSessionListeners">
            <list>
                <ref bean="httpSessionMonitorListener"/>
            </list>
        </property>
	</bean>
	
</beans>

2、属性文件config.properties配置如下:

## redis pool config
redis.pool.maxTotal=100
redis.pool.maxIdle=20
redis.pool.minIdle=10
redis.pool.blockWhenExhausted=true
redis.pool.maxWaitMillis=3000
redis.pool.testOnBorrow=false
redis.pool.testOnReturn=false
redis.pool.testWhileIdle=true
redis.pool.minEvictableIdleTimeMillis=60000
redis.pool.timeBetweenEvictionRunsMillis=30000
redis.pool.numTestsPerEvictionRun=-1

# redis config
redis.host=192.168.0.123
redis.port=6379
redis.password=admin-123456
redis.database=0
redis.timeout=3600

3、web.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>editor</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext.xml,classpath:spring/applicationContext-security.xml</param-value>
	</context-param>

	<listener>  
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>  
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>
	
	<!-- CAS 单点退出 -->
	<filter>
		<filter-name>CAS Single Sign Out Filter</filter-name>
		<filter-class>com.wuzb.pw.common.shiro.CustomSingleSignOutFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>CAS Single Sign Out Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- POST乱码处理 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<async-supported>true</async-supported>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<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> 

	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/applicationContext-mvc.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file></welcome-file>
	</welcome-file-list>
	
</web-app>

项目中使用的Spring版本4.1.6.RELEASE。其中集成Spring Session所需的Jar如下:

spring-data-commons-1.12.3.RELEASE.jar
spring-data-keyvalue-1.1.3.RELEASE.jar
spring-data-redis-1.7.1.RELEASE.jar
spring-session-1.2.2.RELEASE.jar
spring-session-data-redis-1.2.2.RELEASE.jar
jedis-2.8.1.jar

需要注意的点:

spring-session-data-redis-1.2.2.RELEASE.jar默认依赖spring-data-redis-1.7.1.RELEASE.jar,

若使用spring-data-redis-1.7.3.RELEASE或者更高版本的会出现如下异常:

Caused by: java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.<init>(Ljava/lang/ClassLoader;)V
	at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.<init>(JdkSerializationRedisSerializer.java:53)
	at org.springframework.data.redis.core.RedisTemplate.afterPropertiesSet(RedisTemplate.java:119)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
	... 49 more

    在处理分布式Session的案例中,有很多种解决方案。例如基于Tomcat中间件(TomcatRedisSessionManager)基于服务器基本做会话共享(局限大);基于SpringSession插件实现Session共享;若使用Shiro权限框架还可以自己实现SessionDao来实现Session共享。这些在后续时间里,再继续探索。

看完上述内容,你们对基于Spring-Session如何实现会话共享有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注天达云行业资讯频道,感谢大家的支持。

返回云计算教程...