spring session通過redis存儲,實現session共享

web開發中session一直都是做分佈式集羣應用時需要解決的一個難題,前面寫了tomcat服務器集羣的文章,那麼集羣中怎麼實現session共享呢?

讓我們回顧一下,Tomcat集羣搭建(APACHE+MOD_JK+TOMCAT配置)的session共享是直接通過tomcat自帶的複製功能,即訪問其中一臺tomcat服務器就會在其他配置好的tomcat服務器上各複製一份session,這樣的session共享可能會存在一定的延遲,同時若併發量一大的話也會有網絡風暴的風險;而Tomcat集羣搭建(nginx+tomcat+redis)的session共享是通過第三方redis來存儲session來實現的,這種方式以前比較流行,但是這種也是需要依賴於tomcat(需要修改tomcat的context.xml的配置),而且現在官方也沒去更新tomcat-redis-session-manager的jar包了(仍然停留在支持tomcat7上,一些自己修改的jar包除外)。

本文我要說的session共享,就是獨立於servlet容器、session存儲在第三方存儲容器redis的spring session。它不用擔心併發量大時的網絡風暴;不用擔心換容器運行時,又需要各種各樣的配置;不用擔心servlet容器(即這裏的tomcat)停止服務了,session就不存在了,用戶又得重新登陸的麻煩。因爲spring session的實現是在項目的配置,以及代碼中的。

在開始之前,讓我們先了解一下spring session實現session共享,以及在spring框架中實現的原理。

spring session通過redis來實現多個服務器間的session共享的原理,其實就是將session獨立出來不依賴原來的web容器,而是存放到與web容器沒有耦合關係的redis容器中,這樣即使是任何一臺web容器掛了,也不會影響到其中的session,如下圖所示:

spring session在spring框架中的實現原理,其實就是在請求request上通過DelegatingFilterProxy代理過濾器封裝了一層,將原來存儲在容器緩存的session變成存儲在redis的session,所以在web.xml中的此filter必須得是在所有filter的前面。具體的web容器加載過程,如下圖所示:

 

1 準備工作

這裏的準備工作有幾點,redis存儲容器、spring框架的jar包(需要在spring框架的環境下)和spring session的相關jar包。其中redis存儲容器,我就不多說了,網上有很多redis的安裝教程,或者參考此處redis的安裝

1.1 spring框架的jar包

若你的項目原本就有spring框架的,忽略此準備工作。

注意:這裏用的spring都是比較高版本的,最好用本文的相應版本,否則會出現一些版本不合的奇葩錯誤

commons-logging選擇1.2版本:http://commons.apache.org/proper/commons-logging/download_logging.cgi

spring-aop選擇5.0.8版本:http://www.mvnrepository.com/artifact/org.springframework/spring-aop

spring-beans選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-beans

spring-context選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-context

spring-core選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-core

spring-expression選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-expression

spring-web選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-web

spring-webmvc選擇5.0.8版本:http://www.mvnrepository.com/artifact/org.springframework/spring-webmvc

spring-tx選擇5.0.8版本:http://mvnrepository.com/artifact/org.springframework/spring-tx

 

1.2 spring session的相關jar包

注意:這裏用的spring session都是比較高版本的,最好用本文的相應版本,否則會出現一些版本不合的奇葩錯誤

commons-pool2選擇2.6.0版本:http://commons.apache.org/proper/commons-pool/download_pool.cgi

jedis選擇2.9.0版本:http://central.maven.org/maven2/redis/clients/jedis/

spring-data-commons選擇2.0.9版本:https://repo.spring.io/libs-release/org/springframework/data/spring-data-commons/

spring-data-redis選擇2.0.9版本:https://repo.spring.io/libs-release/org/springframework/data/spring-data-redis/

spring-session-core選擇2.0.5版本:http://mvnrepository.com/artifact/org.springframework.session/spring-session-core

spring-session-data-redis選擇2.0.5版本:https://repo.spring.io/libs-release/org/springframework/session/spring-session-data-redis/

 

2 具體步驟

2.1 創建項目

(1)在eclipse中創建一個web項目,命名爲SpringSession。

(2)將上面下載的jar包全放到項目中WEB-INF/lib目錄下。

 

2.2 spring mvc的配置

(1)在源碼的src目錄下創建config放置配置文件的包,以及創建com.sky.springsession放置java源碼的包。

(2)在config包下創建applicationContext.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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd 
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.sky.springsession"/>
    
    <context:annotation-config/>

</beans>

這是spring mvc的最基本的配置,當然這些配置在這裏其實也是可以免去的。

 

2.3 spring session的配置

在config包下創建spring-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:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="10"/><!-- 最大空閒連接數, 默認8個 -->
        <property name="maxTotal" value="20"/><!-- 最大連接數, 默認8個 -->
        <property name="blockWhenExhausted" value="true"/><!-- 連接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true -->
        <property name="maxWaitMillis" value="1000"/><!-- 獲取連接時的最大等待毫秒數(如果設置爲阻塞時BlockWhenExhausted),如果超時就拋異常, 小於零:阻塞不確定的時間,  默認-1 -->
        <property name="testOnBorrow" value="true"/><!-- 在獲取連接的時候檢查有效性, 默認false -->
    </bean>
    
    <!-- redis連接配置,依次爲主機ip,端口,密碼,是否使用池,連接池配置引用 -->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
        p:host-name="192.168.17.132" p:port="6379" p:password="123456" p:usePool="true" p:pool-config-ref="jedisPoolConfig">
    </bean>
    
    <!-- 配置spring-session -->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!-- session過期時間,單位是秒 -->
        <property name="maxInactiveIntervalInSeconds" value="30"></property>
    </bean>
</beans>

注意,用了spring session後,在web.xml設置的session過期時間是無效。因爲此session已經不是原來的存儲在容器緩存內的session了,而是被封裝多了一層後存儲在redis的session。

 

2.4 web.xml的配置

在web.xml文件添加如下代碼

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:config/*.xml</param-value>
  </context-param>
  
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  

  <!-- spring session的過濾器配置,注意此過濾器必須放在其他過濾器之前 -->
  <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>
  
  <!-- springmvc配置 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 通過初始化參數,指定xml文件的位置 -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:config/applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

配置至此,就能夠實現spring session通過存儲到redis的session共享了。

 

3 測試

3.1 創建jsp測試文件

(1)在WebContent目錄下創建index.jsp,放置如下代碼

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.Date" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>spring session</title>
</head>
<body>
<%
System.out.println(new Date()+"=============tomcat1=================");
session.setAttribute("tomcat1", "I am tomcat1");
%>

<h1>hello world!</h1><br>
<p><%=session.getId()%>======<%=new Date()%></p>
<p>tomcat1======<%=session.getAttribute("tomcat1")%></p>
<p>tomcat2======<%=session.getAttribute("tomcat2")%></p>
</body>
</html>

 

(2)在WebContent目錄下創建result.jsp,放置如下代碼

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.Date" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>spring session</title>
</head>
<body>
<h1>result tomcat1</h1><br>
<p><%=session.getId()%>======<%=new Date()%></p>
<p>tomcat1======<%=session.getAttribute("tomcat1")%></p>
<p>tomcat2======<%=session.getAttribute("tomcat2")%></p>
</body>
</html>

 

3.2 開始測試

(1)打開瀏覽器,輸入url:http://localhost:8080/SpringSession/

 

(2)打開第二個標籤頁

 

(3)待30秒過後,刷新第二個標籤頁,發現tomcat1已經爲null,說明上面的spring session的過期時間設置是有效的。

 

(4)當然想要看下spring session是否真的存在了redis,也可以到redis客戶端上查看。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章