天天看點

Springboot和Spring Session實作session共享

HttpSession是通過Servlet容器建立和管理的,像Tomcat/Jetty都是儲存在記憶體中的。而如果我們把web伺服器搭建成分布式的叢集,然後利用LVS或Nginx做負載均衡,那麼來自同一使用者的Http請求将有可能被分發到兩個不同的web站點中去。那麼問題就來了,如何保證不同的web站點能夠共享同一份session資料呢?

最簡單的想法就是把session資料儲存到記憶體以外的一個統一的地方,例如Memcached/Redis等資料庫中。

那麼問題又來了,如何替換掉Servlet容器建立和管理HttpSession的實作呢?

設計一個Filter,利用HttpServletRequestWrapper,實作自己的 getSession()方法,接管建立和管理Session資料的工作。spring-session就是通過這樣的思路實作的。

使用Spring Session和Redis的組合來代替原有的HttpSession實作Session在不同項目之間的共享

在springboot中內建Spring Session

引入spring session相關依賴

<!-- spring session -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
           

添加 SpringSession 配置類

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class HttpSessionConfig {
        //不需要寫任何代碼
}
           

配置類中最關鍵的就是

@EnableRedisHttpSession

@EnableRedisHttpSession

注解建立了一個名為

springSessionRepositoryFilter

bean

,負責替換

httpSession

,同時由

redis

提供緩存支援

為了做到全部替換,我們要確定Servlet容器(Tomcat)對于某個請求都使用這個Filter,這個由SpringBoot負責

(具體是這樣的:

@EnableRedisHttpSession

注解通過

Import

,引入了

RedisHttpSessionConfiguration

配置類。該配置類通過

@Bean

注解,向Spring容器中注冊了一個

SessionRepositoryFilter

(SessionRepositoryFilter的依賴關系:SessionRepositoryFilter --> SessionRepository --> RedisTemplate --> RedisConnectionFactory,有興趣可以檢視源碼)

maxInactiveIntervalInSeconds

:設定

Session

失效時間,使用

Redis Session

之後,原

springboot

server.session.timeout

屬性不再生效

添加驗證的接口

yml

或者

properties

檔案中可以通過server.port設定端口

@Value("${server.port}")
    String port;

    @GetMapping("/session")
    public Object getSession(HttpServletRequest request){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("SessionId", request.getSession().getId());
        map.put("ServerPort", "服務端口号為 "+port);
        return map;
    }
           

通路

http://localhost:8080/session

Paste_Image.png

我們看下redis緩存的資料

可以發現

sessionId

已經緩存在redis資料庫中

下面我們換個端口再通路一次看看

這次我把端口換成了8888 通路:

http://localhost:8888/session

重新整理了redis資料庫,緩存的資料也沒變

結果中的SessionId是一緻的,卻是由兩個不同項目工程來提供服務。這樣子,SpringSession 利用攔截器 Filter 幫我們在每個請求前進行了同步設定,達到了分布式系統中 session 共享。