内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫

本篇文章為大家展示了使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

成都創(chuàng)新互聯(lián)主營(yíng)貢山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都APP應(yīng)用開發(fā),貢山h5微信小程序定制開發(fā)搭建,貢山網(wǎng)站營(yíng)銷推廣歡迎貢山等地區(qū)企業(yè)咨詢

1、請(qǐng)求重寫

SpringSession 中對(duì)于請(qǐng)求重寫,在能力上主要體現(xiàn)在存儲(chǔ)方面,也就是 getSession 方法上。在 SessionRepositoryFilter 這個(gè)類中,是通過(guò)內(nèi)部類的方式實(shí)現(xiàn)了對(duì) HttpServletRequsetHttpServletResponse 的擴(kuò)展。

1.1 HttpServletRequset 擴(kuò)展實(shí)現(xiàn)

private final class SessionRepositoryRequestWrapper
			extends HttpServletRequestWrapper {
	// HttpServletResponse 實(shí)例
	private final HttpServletResponse response;
	// ServletContext 實(shí)例
	private final ServletContext servletContext;
 // requestedSession session對(duì)象
 private S requestedSession; 
 // 是否緩存 session
 private boolean requestedSessionCached;
	// sessionId
	private String requestedSessionId;
	// sessionId 是否有效
	private Boolean requestedSessionIdValid;
	// sessionId 是否失效
	private boolean requestedSessionInvalidated;
	
	// 省略方法
}

1.2 構(gòu)造方法

private SessionRepositoryRequestWrapper(HttpServletRequest request,
		HttpServletResponse response, ServletContext servletContext) {
	super(request);
	this.response = response;
	this.servletContext = servletContext;
}

構(gòu)造方法里面將 HttpServletRequest 、 HttpServletResponse 以及 ServletContext 實(shí)例傳遞進(jìn)來(lái),以便于后續(xù)擴(kuò)展使用。

1.3 getSession 方法

@Override
public HttpSessionWrapper getSession(boolean create) {
 // 從當(dāng)前請(qǐng)求線程中獲取 session
	HttpSessionWrapper currentSession = getCurrentSession();
	// 如果有直接返回
	if (currentSession != null) {
		return currentSession;
	}
	// 從請(qǐng)求中獲取 session,這里面會(huì)涉及到從緩存中拿session的過(guò)程
	S requestedSession = getRequestedSession();
	if (requestedSession != null) {
	 // 無(wú)效的會(huì)話id(不支持的會(huì)話存儲(chǔ)庫(kù))請(qǐng)求屬性名稱。
	 // 這里看下當(dāng)前的sessionId是否有效
		if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
		 // 設(shè)置當(dāng)前session的最后訪問(wèn)時(shí)間,用于延遲session的有效期
			requestedSession.setLastAccessedTime(Instant.now());
			// 將requestedSessionIdValid置為true
			this.requestedSessionIdValid = true;
			// 包裝session
			currentSession = new HttpSessionWrapper(requestedSession, getServletContext());
			// 不是新的session,如果是新的session則需要改變sessionId
			currentSession.setNew(false);
			// 將session設(shè)置到當(dāng)前請(qǐng)求上下文
			setCurrentSession(currentSession);
			// 返回session
			return currentSession;
		}
	}
	else {
		// 這里處理的是無(wú)效的sessionId的情況,但是當(dāng)前請(qǐng)求線程 session有效
		if (SESSION_LOGGER.isDebugEnabled()) {
			SESSION_LOGGER.debug(
					"No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
		}
		// 將invalidSessionId置為true
		setAttribute(INVALID_SESSION_ID_ATTR, "true");
	}
	// 是否需要?jiǎng)?chuàng)建新的session
	if (!create) {
		return null;
	}
	if (SESSION_LOGGER.isDebugEnabled()) {
		SESSION_LOGGER.debug(
				"A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
						+ SESSION_LOGGER_NAME,
				new RuntimeException(
						"For debugging purposes only (not an error)"));
	}
	// 創(chuàng)建新的session
	S session = SessionRepositoryFilter.this.sessionRepository.createSession();
	// 設(shè)置最后訪問(wèn)時(shí)間,也就是指定了當(dāng)前session的有效期限
	session.setLastAccessedTime(Instant.now());
	// 包裝下當(dāng)前session
	currentSession = new HttpSessionWrapper(session, getServletContext());
	//設(shè)置到當(dāng)前請(qǐng)求線程
	setCurrentSession(currentSession);
	return currentSession;
}

上面這段代碼有幾個(gè)點(diǎn),這里單獨(dú)來(lái)解釋下。

getCurrentSession

這是為了在同一個(gè)請(qǐng)求過(guò)程中不需要重復(fù)的去從存儲(chǔ)中獲取session,在一個(gè)新的進(jìn)來(lái)時(shí),將當(dāng)前的 session 設(shè)置到當(dāng)前請(qǐng)求中,在后續(xù)處理過(guò)程如果需要getSession就不需要再去存儲(chǔ)介質(zhì)中再拿一次。

getRequestedSession

這個(gè)是根據(jù)請(qǐng)求信息去取 session ,這里面就包括了 sessionId 解析,從存儲(chǔ)獲取 session 對(duì)象等過(guò)程。

是否創(chuàng)建新的 session 對(duì)象

在當(dāng)前請(qǐng)求中和存儲(chǔ)中都沒(méi)有獲取到 session 信息的情況下,這里會(huì)根據(jù) create 參數(shù)來(lái)判斷是否創(chuàng)建新的 session 。這里一般用戶首次登錄時(shí)或者 session 失效時(shí)會(huì)走到。

1.4 getRequestedSession

根據(jù)請(qǐng)求信息來(lái)獲取 session 對(duì)象

private S getRequestedSession() {
 // 緩存的請(qǐng)求session是否存在
	if (!this.requestedSessionCached) {
  // 獲取 sessionId
  List<String> sessionIds = SessionRepositoryFilter.this.httpSessionIdResolver
  		.resolveSessionIds(this);
  // 通過(guò)sessionId來(lái)從存儲(chǔ)中獲取session
  for (String sessionId : sessionIds) {
  	if (this.requestedSessionId == null) {
  		this.requestedSessionId = sessionId;
  	}
  	S session = SessionRepositoryFilter.this.sessionRepository
  			.findById(sessionId);
  	if (session != null) {
  		this.requestedSession = session;
  		this.requestedSessionId = sessionId;
  		break;
  	}
  }
  this.requestedSessionCached = true;
	}
	return this.requestedSession;
}

這段代碼還是很有意思的,這里獲取 sessionId 返回的是個(gè)列表。當(dāng)然這里是 SpringSession 的實(shí)現(xiàn)策略,因?yàn)橹С?session ,所以這里以列表的形式返回的。OK,繼續(xù)來(lái)看如何解析 sessionId 的:

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫

這里可以看到 SpringSession 對(duì)于 sessionId 獲取的兩種策略,一種是基于 cookie ,一種是基于 header ;分別來(lái)看下具體實(shí)現(xiàn)。

1.4.1 CookieHttpSessionIdResolver 獲取 sessionId

CookieHttpSessionIdResolver 中獲取 sessionId 的核心代碼如下:

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫 

其實(shí)這里沒(méi)啥好說(shuō)的,就是讀 cookie 。從 requestcookie 信息拿出來(lái),然后遍歷找當(dāng)前 sessionId 對(duì)應(yīng)的 cookie ,這里的判斷也很簡(jiǎn)單, 如果是以 SESSION 開頭,則表示是 SessionId ,畢竟 cookie 是共享的,不只有 sessionId,還有可能存儲(chǔ)其他內(nèi)容。

另外這里面有個(gè) jvmRoute,這個(gè)東西實(shí)際上很少能夠用到,因?yàn)榇蠖鄶?shù)情況下這個(gè)值都是null。這個(gè)我們?cè)诜治?CookieSerializer 時(shí)再來(lái)解釋。

1.4.2 HeaderHttpSessionIdResolver 獲取 sessionId

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫 

這個(gè)獲取更直接粗暴,就是根據(jù) headerNameheader中取值。

回到 getRequestedSession ,剩下的代碼中核心的都是和 sessionRepository 這個(gè)有關(guān)系,這部分就會(huì)涉及到存儲(chǔ)部分。不在本篇的分析范圍之內(nèi),會(huì)在存儲(chǔ)實(shí)現(xiàn)部分來(lái)分析。

1.5 HttpSessionWrapper

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫

上面的代碼中當(dāng)我們拿到 session 實(shí)例是通常會(huì)包裝下,那么用到的就是這個(gè) HttpSessionWrapper 。

HttpSessionWrapper 繼承了 HttpSessionAdapter ,這個(gè) HttpSessionAdapter 就是將SpringSession 轉(zhuǎn)換成一個(gè)標(biāo)準(zhǔn) HttpSession 的適配類。 HttpSessionAdapter 實(shí)現(xiàn)了標(biāo)準(zhǔn) servlet 規(guī)范的 HttpSession 接口。

1.5.1 HttpSessionWrapper

HttpSessionWrapper 重寫了 invalidate 方法。從代碼來(lái)看,調(diào)用該方法產(chǎn)生的影響是:

  • requestedSessionInvalidated 置為 true ,標(biāo)識(shí)當(dāng)前 session 失效。

  • 將當(dāng)前請(qǐng)求中的 session 設(shè)置為 null ,那么在請(qǐng)求的后續(xù)調(diào)用中通過(guò) getCurrentSession 將拿不到 session 信息。

  • 當(dāng)前緩存的 session 清楚,包括sessionId,session實(shí)例等。

  • 刪除存儲(chǔ)介質(zhì)中的session對(duì)象。

 1.5.2 HttpSessionAdapter

SpringSession 和標(biāo)準(zhǔn) HttpSession 的配置器類。這個(gè)怎么理解呢,來(lái)看下一段代碼:

@Override
public Object getAttribute(String name) {
	checkState();
	return this.session.getAttribute(name);
}

對(duì)于基于容器本身實(shí)現(xiàn)的 HttpSession 來(lái)說(shuō), getAttribute 的實(shí)現(xiàn)也是有容器本身決定。但是這里做了轉(zhuǎn)換之后, getAttribute 將會(huì)通過(guò) SpringSession 中實(shí)現(xiàn)的方案來(lái)獲取。其他的 API 適配也是基于此實(shí)現(xiàn)。

SessionCommittingRequestDispatcher

實(shí)現(xiàn)了 RequestDispatcher 接口。關(guān)于 RequestDispatcher 可以參考這篇文章【Servlet】關(guān)于RequestDispatcher的原理 。 SessionCommittingRequestDispatcher 對(duì) forward 的行為并沒(méi)有改變。 對(duì)于 include 則是在 include 之前提交 session 。為什么這么做呢?

因?yàn)?include 方法使原先的 Servlet 和轉(zhuǎn)發(fā)到的 Servlet 都可以輸出響應(yīng)信息,即原先的 Servlet 還可以繼續(xù)輸出響應(yīng)信息;即請(qǐng)求轉(zhuǎn)發(fā)后,原先的 Servlet 還可以繼續(xù)輸出響應(yīng)信息,轉(zhuǎn)發(fā)到的 Servlet 對(duì)請(qǐng)求做出的響應(yīng)將并入原先 Servlet 的響應(yīng)對(duì)象中。

所以這個(gè)在 include 調(diào)用之前調(diào)用 commit ,這樣可以確保被包含的 Servlet 程序不能改變響應(yīng)消息的狀態(tài)碼和響應(yīng)頭。

2 響應(yīng)重寫

響應(yīng)重寫的目的是確保在請(qǐng)求提交時(shí)能夠把session保存起來(lái)。來(lái)看下 SessionRepositoryResponseWrapper 類的實(shí)現(xiàn):

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫 

這里面實(shí)現(xiàn)還就是重寫 onResponseCommitted ,也就是上面說(shuō)的,在請(qǐng)求提交時(shí)能夠通過(guò)這個(gè)回調(diào)函數(shù)將 session

保存到存儲(chǔ)容器中。

2.1 session 提交

最后來(lái)看下 commitSession

使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫

這個(gè)過(guò)程不會(huì)再去存儲(chǔ)容器中拿 session 信息,而是直接從當(dāng)前請(qǐng)求中拿。如果拿不到,則在回寫 cookie 時(shí)會(huì)將當(dāng)前 session 對(duì)應(yīng)的 cookie 值設(shè)置為空,這樣下次請(qǐng)求過(guò)來(lái)時(shí)攜帶的 sessionCookie 就是空,這樣就會(huì)重新觸發(fā)登陸。

如果拿到,則清空當(dāng)前請(qǐng)求中的 session 信息,然后將 session 保存到存儲(chǔ)容器中,并且將 sessionId 回寫到 cookie 中。

上述內(nèi)容就是使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

文章題目:使用SpringSession怎么實(shí)現(xiàn)請(qǐng)求與響應(yīng)重寫
文章位置:http://www.rwnh.cn/article40/jgpdho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站改版、企業(yè)網(wǎng)站制作靜態(tài)網(wǎng)站、網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)
正阳县| 泸州市| 乐陵市| 天祝| 太仆寺旗| 新化县| 逊克县| 古丈县| 清远市| 房产| 南丹县| 东辽县| 图木舒克市| 温州市| 淮北市| 涞源县| 贺兰县| 邵阳市| 陈巴尔虎旗| 腾冲县| 本溪市| 甘泉县| 五原县| 广宗县| 宣武区| 临城县| 无为县| 万宁市| 昌都县| 博乐市| 山东省| 宁南县| 泸西县| 千阳县| 三都| 攀枝花市| 丁青县| 武冈市| 沂水县| 芮城县| 买车|