1. 程式人生 > >解決shiro redis 重寫sessiondao多次查詢Redis問題

解決shiro redis 重寫sessiondao多次查詢Redis問題

發現 一直呼叫 sessiondao 的 doReadSession 方法
doReadSession 
doCreate 
update 
doReadSession  
update 
doReadSession  
doReadSession  
update
常常還出現這個異常

 Caused by: org.apache.shiro.session.UnknownSessionException: There is no session with id [517a249d-f921-43c4-8c07-c9c6e4cfba73]

解決方式:

這個是shiro  設計上的問題, 主要是因為shiro 框架獲取 session裡面的屬性時,每次都去拿取session,一次請求中會有很多次 獲取 session 裡面的屬性。

我的解決思路是首先獲取Spring啟動後獲取可請求的地址,然後放到快取中,Shiro框架是基於過濾器實現的,我在進入Shiro的過濾器前先判定當前請求是否合法,如果合法的話,進入下一個過濾器,不合法的話返回提示,然後也不去Redis中進行查詢。

以下基於Spring Boot框架

1.建立一個監聽獲取Spring啟動後可訪問的地址

package com.abroad.common.listener;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.abroad.common.cache.LocalCache;

/**
 * 當容器啟動時獲取當前容器的可請求地址,並把它放到快取中
 * 
 * @ClassName: RequestURLListener
 * @Description: TODO()
 * @author: mengxr
 * @date 2017年3月29日 下午6:25:36
 */
public class RequestUrlListener implements
		ApplicationListener<ContextRefreshedEvent> {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		if (event.getApplicationContext().getParent() == null) {// root application context 沒有parent,他就是老大.
			try {
				ApplicationContext applicationContext = event
						.getApplicationContext();
				RequestMappingHandlerMapping bean = applicationContext
						.getBean(RequestMappingHandlerMapping.class);
				Set<String> result = new HashSet<String>();
				Map<RequestMappingInfo, HandlerMethod> handlerMethods = bean
						.getHandlerMethods();
				for (RequestMappingInfo rmi : handlerMethods.keySet()) {
					PatternsRequestCondition pc = rmi.getPatternsCondition();
					Set<String> pSet = pc.getPatterns();
					result.addAll(pSet);
				}
				LocalCache.ACCESS_URL.addAll(result);
				logger.info("-----------初始化RequestUrlListener成功 ");
			} catch (Exception e) {
				logger.error("-----------獲取RequestUrlListener失敗 ",e);
			}
		}
	}
}
然後在SpringBoot啟動時註冊監聽
package com.abroad;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.abroad.common.listener.RequestUrlListener;

/**
* @ClassName: SecurityApplication
* @Description: TODO(許可權管理框架)
* @author: mengxr
* @date 2017年3月23日 上午10:52:13
*/
@SpringBootApplication
public class SecurityApplication {
    public static void main(String[] args) {
    	SpringApplication springApplication = new SpringApplication(SecurityApplication.class);
    	springApplication.addListeners(new RequestUrlListener()); //新增一個啟動後監聽
    	springApplication.run(args);
    }
}
2.獲取到可訪問的URL地址後建立一個過濾器Filter
package com.abroad.common.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.abroad.common.cache.LocalCache;
import com.abroad.common.comn.ResponseJson;
import com.abroad.common.comn.StatusCode;
import com.abroad.common.comn.web.ServletTools;

/**
* @ClassName: AccessFilter
* @Description: TODO(訪問過濾器)
* @author: mengxr
* @date 2017年3月29日 下午6:08:54
*/
public class AccessFilter implements Filter {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
    	String url = ServletTools.getContextPath((HttpServletRequest)request);
    	boolean flag = LocalCache.ACCESS_URL.contains(url);
    	if(flag){ //如果還有的話繼續走下一個過濾器
            chain.doFilter(request, response);
    	}else{
    		//沒有找到相應的資源
    		ServletTools.sendResponse((HttpServletResponse) response, new ResponseJson(StatusCode.NOT_FOUND, false));
    	}
    }

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		logger.info("訪問過濾器AccessFilter註冊成功----");
	}

	@Override
	public void destroy() {
		logger.info("訪問過濾器AccessFilter摧毀成功-----");
	}
 
}
SpringBoot註冊過濾器
package com.abroad.common.config;

import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import com.abroad.common.filter.AccessFilter;

/**
 * 
* @ClassName: AccessConfigue
* @Description: TODO(訪問控制)
* @author: mengxr
* @date 2017年3月29日 下午5:58:39
*/
@Configuration
public class AccessConfigue {
    /**
     * 由於shrio框架在每次請求的時候都要向快取查詢當前的Session效率十分低,並且shrio框架是基於過濾器實現的,
     * 所以在進入shrioFilter前先對訪問的資料進行過濾,如果不存在的換直接跳轉到404狀態
    * @Title: accessFilterRegistration
    * @Description: TODO(這裡用一句話描述這個方法的作用)
    * @param @return    設定檔案
    * @return FilterRegistrationBean    返回型別
    * @author: mengxr
    * @date 2017年3月29日 下午6:03:17
    * @throws
    */
    @Bean
    @Order(Integer.MAX_VALUE) //攔截器優先順序最高
    public FilterRegistrationBean accessFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        AccessFilter accessFilter = new AccessFilter();
        registration.setFilter(accessFilter);
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setName("accessFilter");
        return registration;
    }
}
PS: 此處  @Order是攔截器的優先順序  要優於Shrio的攔截器先

3.啟動服務 發現AcceeFilter要由於shiroFilter先執行

4.測試結果  再次訪問URL後發現已不再進行Redis查詢


相關推薦

解決shiro redis 重寫sessiondao查詢Redis問題

發現 一直呼叫 sessiondao 的 doReadSession 方法 doReadSession  doCreate  update  doReadSession   update  doReadSession   doReadSession   update 常常還

解決 springboot整合shiroredis快取session redis獲取session問題

    spring boot整合shiro redis快取session的教程很多,我這裡就不多說了,看了好多教程沒有解決快取session 多次從redis獲取session的問題,所以發表此部落格,希望對大家有所幫助。本人也是小白一個,如果有什麼問題還請各位大神多多指教

在同一事務中,mybatis查詢返回相同結果解決方法

一、問題描述: 使用spring @Transaction事務時,在for迴圈中需要多次執行同一查詢語句,第一次查詢出物件後,對物件進行修改後,結果再進行第二次查詢的時候,查詢返回的資料是自己第一次修改後的資料。因為業務需要每次查詢都需要取更改資料庫,以後的查詢都會根據上一次迴圈修改後的值進行操

優化 shiro 呼叫 redis 的問題

我們常使用 Shiro + redis 的組合解決叢集下的 Session 共享問題,這裡就不展開如何整合的問題了。 在進行日常優化的過程中,我通過日誌發現這麼一段日誌: 2017-09-17 15:16:07.723 -DEBUG [nio-8080-exec-6] o

解決Javascript中$(window).resize()執行(轉)

https://www.cnblogs.com/shuilangyizu/p/6816756.html 有些時候,我們需要在瀏覽器視窗發生變化的時候,動態的執行一些操作,比如做自適應頁面時的適配。這個時候,我們需要在視窗拖動的時候去執行程式碼。但是有些時候,執行的操作比較複雜,我們只希望在視窗拖動完畢之後,

【codeforces 617E XOR and Favorite Number】【莫隊分塊】【查詢求區間[l,r]中區間異或等於k的子區間個數】

【連結】 【題意】 給定一個數組,多次查詢,問區間l,r中有多少個子區間滿足區間異或為k 【思路】 查詢很大,意味著每次回答的時間複雜度不能太大。對於本題,我們可以維護一個字首異或,sum[i],區間[a,b]異或為k等價於sum[a-1]^sum[b]=k,假如

關聯查詢查詢的點 以及 MySQL慢查詢優化 EXPLAIN詳解

        對於欄位比較多的表,如果有些欄位的使用頻率很低,可以將這些欄位分離出來形成新表。因為當一個表的資料量很大時,會由於使用頻率低的欄位的存在而變慢。2. 增加中間表        對於需要經常聯合查詢的表,可以建立中間表以提高查詢效率。通過建立中間表,把需要經常聯合查詢的資料插入到中間表中,然後將

【微信小程式】下拉載入請求的解決方案,避免使用者發起請求降低業務處理。

方案一:小程式前端:做好請求判斷,請求前:設定常量變為0 ,觸發網路請求介面 常量變為 1,回撥成功常量設定 0 ,每次請求前判斷常量是否為 1,為1 即意味著上次請求回撥沒有接收到。防止多次請求。但是

徹底解決listview,gridview的getview呼叫問題

listview,gridview,有時候getview會呼叫多次,特別是把listview放在viewpager中,很容易卡頓 網上的方法往往只是說,把listview的height固定住或者fill_parent,其實這樣簡單的listview是有效的,但是item如

iOS解決按鈕短時間內點選只觸發一事件方法(開始寫部落格)

在上家公司做專案的時候,做了個60秒獲取驗證碼的功能,當時做了個定時器,按鈕觸發定時器,邏輯來講都是沒問題的,但是實際操作的時候,惡意的在短時間內多次點選那個獲取驗證碼按鈕,按鈕的點選事件被呼叫了多次,定時器從而也呼叫多次,本來一秒減一的事件變成了一秒減多,並且減到0

iOS解決按鈕短時間內點擊只觸發一事件方法

end bind nbsp per dos cancel span 內多 perf - (void)unisversalButtonAcrion:(UIButton *)sender { [[self class] cancelPreviousPerformReq

查詢一段區間內有多少個子區間滿足其中一個端點為區間最大值。

預處理 如果 哪些 class 每一個 祖先 href 貢獻 http 考慮維護出每一個點左邊第一個比它大的位置,右邊同理,這樣有一個合法區間。 然後對詢問離線,由於要求只包含區間內的貢獻,掃描線+線段樹解決。 T1 http://codeforces.com/proble

EntityFramework Core 3Include導致查詢效能低之解決方案

前言 上述我們簡單講解了幾個小問題,這節我們再來看看如標題EF Core中多次Include導致出現效能的問題,廢話少說,直接開門見山。 EntityFramework Core 3多次Include查詢問題 不要嫌棄我囉嗦,我們凡事從頭開始講解起,首先依然給出我們上一節的示例類: pub

使用fdmemTable來代替clientDataset,解決MySQL5.6(含)以上版本用cds更新時的錯誤

提交 sage string fdm pos final .text .post 1.5 //讀取mysql保存到fdMemTable中 procedure TForm3.btnOpen1Click(Sender: TObject);var stream, stream2

ubuntu 使用sudo apt-get update 出現 被配置導致無法升級錯誤解決方法

code 開發機 goup 使用 lin logs 配置 周末 ubun 這個周六周末在考慮升級自己GPU開發機,在琢磨使用docker來按轉tensorflow環境,在升級軟件的時候爆出了如下錯誤 在 /etc/apt/sources.list.d/sogoupin

android-繼承BaseAdapter--自己定義適配器,getView運行解決方法

能夠 popu con data ssa baseadapt tracking you idt 定義的getView運行多次的ListView布局: <ListView android:id="@+id/lv_messages"

解決ASP.NET中ServiceStack.Redis每小時6000訪問請求的問題

asp log style ack div net pre 小時 使用 1.可以使用3.0的版本: Install-Package ServiceStack.Redis -Version 3.0 2.使用ServiceStack.Redis.Complete: Ins

jq:mouseover和mouseout觸發解決辦法

mouseover ren div clas 結構 tro 需要 als ldr 區別: mouseover與mouseenter   不論鼠標指針穿過被選元素或其子元素,都會觸發 mouseover 事件。   只有在鼠標指針穿過被選元素時,才會觸發 mouseenter

C#中WebBrowser.DocumentCompleted事件調用問題解決方法

post lin ont display err 框架 center 一個 blank 關於DocumentCompleted事件,MSDN給出的解釋是在文檔加載完畢後執行,但是在我的程序中DocumentCompleted卻被多次調用,查了一下資料,大概出現了以下幾種情

解決一個特定的負載均衡下定時任務執行的問題

nginx負載均衡 項目 post 緩存 日期 多少 size edi 開始 項目每天晚上有個定時任務,把redis緩存數據重新連接數據庫刷新一遍,耗時大約40分鐘。但問題是項目是nginx負載均衡,這個定時任務會執行多次。經過一些思考之後,用以下辦法解決: redis裏加