日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redis session 超时时间_Shiro性能优化:解决Session频繁读写问题

發布時間:2025/3/12 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis session 超时时间_Shiro性能优化:解决Session频繁读写问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方藍色字體,選擇“標星公眾號”

優質文章,第一時間送達

? 作者?|??張永恒

來源 |? urlify.cn/YjEZNj

背景

Shiro 提供了強大的 Session 管理功能,基于 Shiro 實現 Session 共享非常方便,只需要定制一個我們自己的SessionDAO,并將它綁定給 SessionManager 即可。在我們的 SessionDAO 中,通常會將 Session 保存到 Redis,那么 Shiro 對 Session 的增刪改查,都會直接操作 Redis。

但是由于 Shiro 對 Session 的訪問非常頻繁,用戶的一次請求,可能就會觸發幾十次的 Session 訪問操作,在 Session 共享的場景下,如果每次都訪問 Redis,勢必會影響性能。

應對思路

本地緩存 Session

將 Session 對象緩存于本地內存中,能夠有效減少從 Redis 中讀取 Session 的次數。

最簡單的方案,就是將 Session 對象保存到 request 域中,那么在一次請求內,只需要從 Redis 中獲取一次,之后就可以直接從當前 request 域中獲取,并且當請求結束后緩存會自動銷毀,不用擔心內存泄漏。

避免不必要的 Session 更新

ShiroFilter 對每個請求都會檢查 Session 是否存在,如果存在,則調用 SessionManager 的 touch() 方法,將 Session 的 lastAccessTime 屬性值更新為當前時間,并調用 SessionDAO 的 update() 方法保存更新。

由此可見,當 Session 被創建出來之后,用戶的每個請求都會使 SessionDAO 的 update() 方法至少被調用一次。

那么 Session 的 lastAccessTime 屬性是干嘛用的呢?有必要每個請求都去更新一下嗎?

lastAccessTime 屬性記錄的是用戶的上次訪問時間,它主要用于驗證 Session 是否超時,當用戶訪問系統時,如果本次訪問的時間距離上次訪問時間超過了 timeout 閾值,則判定 Session 超時。如果 lastAccessTime 的值不斷更新,那么 Session 就有可能永不超時。因此,更新 lastAccessTime 屬性值的操作可以認為是給 Session “續命”。

既然是“續命”,沒必要每次都“續”(除非命真的很短)。我們可以重寫 SessionManager 的 touch() 方法,在更新過 lastAccessTime 屬性的值后,先不急著保存更新,而是計算一下兩次訪問的時間間隔,只有當它大于某個閾值時,才去主動調用 SessionDAO 的 update() 方法來保存更新。這樣也就大大降低了 Session 更新的頻率。

代碼實現

ShiroSessionDAO.java

@Repository
public?class?ShiroSessionDAO?extends?AbstractSessionDAO?{

????private?static?final?String?SESSION_REDIS_KEY_PREFIX?=?"session:";

????@Autowired
????private?RedisTemplate?redisTemplate;
????@Override
????protected?Serializable?doCreate(Session?session)?{
????????Serializable?sessionId?=?generateSessionId(session);
????????assignSessionId(session,?sessionId);
????????redisTemplate.boundValueOps(SESSION_REDIS_KEY_PREFIX?+?session.getId().toString()).set(session);return?sessionId;
????}
????@Override
????public?void?update(Session?session)?throws?UnknownSessionException?{
????????redisTemplate.boundValueOps(SESSION_REDIS_KEY_PREFIX?+?session.getId().toString()).set(session);
????}
????@Override
????public?void?delete(Session?session)?{
????????redisTemplate.delete(SESSION_REDIS_KEY_PREFIX?+?session.getId().toString());
????????HttpServletRequest?request?=?getRequest();if?(request?!=?null)?{?//?一定要進行空值判斷,因為SessionValidationScheduler的線程也會調用這個方法,而在那個線程中是不存在Request對象的
????????????request.removeAttribute(session.getId().toString());
????????}
????}
????@Override
????protected?Session?doReadSession(Serializable?sessionId)?{
????????HttpServletRequest?request?=?getRequest();if?(request?!=?null)?{
????????????Session?sessionObj?=?(Session)?request.getAttribute(sessionId.toString());if?(sessionObj?!=?null)?{return?sessionObj;
????????????}
????????}
????????Session?session?=?(Session)?redisTemplate.boundValueOps(SESSION_REDIS_KEY_PREFIX?+?sessionId).get();if?(session?!=?null?&&?request?!=?null)?{
????????????request.setAttribute(sessionId.toString(),?session);
????????}return?session;
????}
????@Override
????public?Collection?getActiveSessions()?{
????????Set?keys?=?redisTemplate.keys(SESSION_REDIS_KEY_PREFIX?+?"*");if?(keys?!=?null?&&?!keys.isEmpty())?{
????????????List?sessions?=?redisTemplate.opsForValue().multiGet(keys);if?(sessions?!=?null)?{return?sessions.stream().map(o?->?(Session)?o).collect(Collectors.toList());
????????????}
????????}return?Collections.emptySet();
????}
????private?HttpServletRequest?getRequest()?{
????????ServletRequestAttributes?requestAttributes?=?(ServletRequestAttributes)?RequestContextHolder.getRequestAttributes();return?requestAttributes?!=?null???requestAttributes.getRequest()?:?null;
????}
}

ShiroConfig.java

@Configuration
public?class?ShiroConfig?{

????@Bean
????public?SessionManager?sessionManager(SessionDAO?sessionDAO)?{
????????DefaultWebSessionManager?sessionManager?=?new?DefaultWebSessionManager()?{
????????????@Override?//?重寫touch()方法,降低Session更新的頻率
????????????public?void?touch(SessionKey?key)?throws?InvalidSessionException?{
????????????????Session?session?=?doGetSession(key);
????????????????if?(session?!=?null)?{
????????????????????long?oldTime?=?session.getLastAccessTime().getTime();
????????????????????session.touch();?//?更新訪問時間
????????????????????long?newTime?=?session.getLastAccessTime().getTime();
????????????????????if?(newTime?-?oldTime?>?300000)?{?//?如果兩次訪問的時間間隔大于5分鐘,主動持久化Session
????????????????????????onChange(session);
????????????????????}
????????????????}
????????????}
????????};
????????
????????sessionManager.setSessionDAO(sessionDAO);?//?綁定SessionDAO

????????SimpleCookie?sessionIdCookie?=?new?SimpleCookie("sessionId");
????????sessionIdCookie.setPath("/");
??????? sessionIdCookie.setMaxAge(8 * 60?* 60);?//?單位:秒數
????????sessionManager.setSessionIdCookie(sessionIdCookie);?//?綁定Cookie模版
????????
????????sessionManager.setSessionIdUrlRewritingEnabled(false);
????????sessionManager.setGlobalSessionTimeout(60?*?60?*?1000);
????????sessionManager.setSessionValidationSchedulerEnabled(true);
????????sessionManager.setSessionValidationInterval(2?*?60?*?60?*?1000);
????????sessionManager.setDeleteInvalidSessions(true);
????????
????????return?sessionManager;
????}

????...?略?...

}
@Configuration
public?class?ShiroConfig?{

????@Bean
????public?SessionManager?sessionManager(SessionDAO?sessionDAO)?{
????????DefaultWebSessionManager?sessionManager?=?new?DefaultWebSessionManager()?{
????????????@Override?//?重寫touch()方法,降低Session更新的頻率
????????????public?void?touch(SessionKey?key)?throws?InvalidSessionException?{
????????????????Session?session?=?doGetSession(key);
????????????????if?(session?!=?null)?{
????????????????????long?oldTime?=?session.getLastAccessTime().getTime();
????????????????????session.touch();?//?更新訪問時間
????????????????????long?newTime?=?session.getLastAccessTime().getTime();
????????????????????if?(newTime?-?oldTime?>?300000)?{?//?如果兩次訪問的時間間隔大于5分鐘,主動持久化Session
????????????????????????onChange(session);
????????????????????}
????????????????}
????????????}
????????};
????????
????????sessionManager.setSessionDAO(sessionDAO);?//?綁定SessionDAO

????????SimpleCookie?sessionIdCookie?=?new?SimpleCookie("sessionId");
????????sessionIdCookie.setPath("/");
??????? sessionIdCookie.setMaxAge(8 * 60?* 60);?//?單位:秒數
????????sessionManager.setSessionIdCookie(sessionIdCookie);?//?綁定Cookie模版
????????
????????sessionManager.setSessionIdUrlRewritingEnabled(false);
????????sessionManager.setGlobalSessionTimeout(60?*?60?*?1000);
????????sessionManager.setSessionValidationSchedulerEnabled(true);
????????sessionManager.setSessionValidationInterval(2?*?60?*?60?*?1000);
????????sessionManager.setDeleteInvalidSessions(true);
????????
????????return?sessionManager;
????}

????...?略?...

}

  • 新款SpringBoot在線教育平臺開源了

  • 精品帖子大匯總

  • 一把“樂觀鎖”輕松搞定高并發下的冪等性問題(附視頻教程)

  • 一文搞懂Java8 Lambda表達式(附視頻教程)

感謝點贊支持下哈?

總結

以上是生活随笔為你收集整理的redis session 超时时间_Shiro性能优化:解决Session频繁读写问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。