java forward 修改請求參數_聊聊springboot session timeout參數設置

本文主要介紹下spring boot中對session timeout參數值的設置過程。

ServerProperties

spring-boot-autoconfigure-1.5.8.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/web/ServerProperties.java

@Override

public void customize(ConfigurableEmbeddedServletContainer container) {

if (getPort() != null) {

container.setPort(getPort());

}

if (getAddress() != null) {

container.setAddress(getAddress());

}

if (getContextPath() != null) {

container.setContextPath(getContextPath());

}

if (getDisplayName() != null) {

container.setDisplayName(getDisplayName());

}

if (getSession().getTimeout() != null) {

container.setSessionTimeout(getSession().getTimeout());

}

//......

}

對應的配置如下

server.session.timeout=120

需要注意單位是秒

TomcatEmbeddedServletContainerFactory

spring-boot-1.5.8.RELEASE-sources.jar!/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java

protected void configureContext(Context context,

ServletContextInitializer[] initializers) {

TomcatStarter starter = new TomcatStarter(initializers);

if (context instanceof TomcatEmbeddedContext) {

// Should be true

((TomcatEmbeddedContext) context).setStarter(starter);

}

context.addServletContainerInitializer(starter, NO_CLASSES);

for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {

context.addLifecycleListener(lifecycleListener);

}

for (Valve valve : this.contextValves) {

context.getPipeline().addValve(valve);

}

for (ErrorPage errorPage : getErrorPages()) {

new TomcatErrorPage(errorPage).addToContext(context);

}

for (MimeMappings.Mapping mapping : getMimeMappings()) {

context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());

}

configureSession(context);

for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {

customizer.customize(context);

}

}

private void configureSession(Context context) {

long sessionTimeout = getSessionTimeoutInMinutes();

context.setSessionTimeout((int) sessionTimeout);

if (isPersistSession()) {

Manager manager = context.getManager();

if (manager == null) {

manager = new StandardManager();

context.setManager(manager);

}

configurePersistSession(manager);

}

else {

context.addLifecycleListener(new DisablePersistSessionListener());

}

}

private long getSessionTimeoutInMinutes() {

long sessionTimeout = getSessionTimeout();

if (sessionTimeout > 0) {

sessionTimeout = Math.max(TimeUnit.SECONDS.toMinutes(sessionTimeout), 1L);

}

return sessionTimeout;

}

這里要注意一下,它內部轉成分鐘,然后設置給tomcat原生的StandardContext

可以從源碼看到,如果設置小于60秒的話,則會默認取1分鐘

StandardContext

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/core/StandardContext.java

@Override

public void setSessionTimeout(int timeout) {

int oldSessionTimeout = this.sessionTimeout;

/*

* SRV.13.4 ("Deployment Descriptor"):

* If the timeout is 0 or less, the container ensures the default

* behaviour of sessions is never to time out.

*/

this.sessionTimeout = (timeout == 0) ? -1 : timeout;

support.firePropertyChange("sessionTimeout",

oldSessionTimeout,

this.sessionTimeout);

}

這一步就是設置給原生的tomcat的StandardContext

session失效的計算

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/session/StandardSession.java

/**

* Return the isValid flag for this session.

*/

@Override

public boolean isValid() {

if (!this.isValid) {

return false;

}

if (this.expiring) {

return true;

}

if (ACTIVITY_CHECK && accessCount.get() > 0) {

return true;

}

if (maxInactiveInterval > 0) {

int timeIdle = (int) (getIdleTimeInternal() / 1000L);

if (timeIdle >= maxInactiveInterval) {

expire(true);

}

}

return this.isValid;

}

這里會去計算timeIdle,然后通過timeIdle的值跟設定的session timeout比較,超出則設置session失效

getIdleTimeInternal

/**

* Return the idle time from last client access time without invalidation check

* @see #getIdleTime()

*/

@Override

public long getIdleTimeInternal() {

long timeNow = System.currentTimeMillis();

long timeIdle;

if (LAST_ACCESS_AT_START) {

timeIdle = timeNow - lastAccessedTime;

} else {

timeIdle = timeNow - thisAccessedTime;

}

return timeIdle;

}

維護了兩個變量,一個是lastAccessedTime,一個是thisAccessedTime

這個是在這個方法中更新

/**

* End the access.

*/

@Override

public void endAccess() {

isNew = false;

/**

* The servlet spec mandates to ignore request handling time

* in lastAccessedTime.

*/

if (LAST_ACCESS_AT_START) {

this.lastAccessedTime = this.thisAccessedTime;

this.thisAccessedTime = System.currentTimeMillis();

} else {

this.thisAccessedTime = System.currentTimeMillis();

this.lastAccessedTime = this.thisAccessedTime;

}

if (ACTIVITY_CHECK) {

accessCount.decrementAndGet();

}

}

正常請求更新

Http11Processor

tomcat-embed-core-8.5.23-sources.jar!/org/apache/coyote/http11/Http11Processor.java

@Override

public SocketState service(SocketWrapperBase> socketWrapper)

throws IOException {

//......

while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&

sendfileState == SendfileState.DONE && !endpoint.isPaused()) {

// ......

// Process the request in the adapter

if (!getErrorState().isError()) {

try {

rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);

getAdapter().service(request, response);

// Handle when the response was committed before a serious

// error occurred. Throwing a ServletException should both

// set the status to 500 and set the errorException.

// If we fail here, then the response is likely already

// committed, so we can't try and set headers.

if(keepAlive && !getErrorState().isError() && !isAsync() &&

statusDropsConnection(response.getStatus())) {

setErrorState(ErrorState.CLOSE_CLEAN, null);

}

} catch (InterruptedIOException e) {

setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);

} catch (HeadersTooLargeException e) {

log.error(sm.getString("http11processor.request.process"), e);

// The response should not have been committed but check it

// anyway to be safe

if (response.isCommitted()) {

setErrorState(ErrorState.CLOSE_NOW, e);

} else {

response.reset();

response.setStatus(500);

setErrorState(ErrorState.CLOSE_CLEAN, e);

response.setHeader("Connection", "close"); // TODO: Remove

}

} catch (Throwable t) {

ExceptionUtils.handleThrowable(t);

log.error(sm.getString("http11processor.request.process"), t);

// 500 - Internal Server Error

response.setStatus(500);

setErrorState(ErrorState.CLOSE_CLEAN, t);

getAdapter().log(request, response, 0);

}

}

// Finish the handling of the request

rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);

if (!isAsync()) {

// If this is an async request then the request ends when it has

// been completed. The AsyncContext is responsible for calling

// endRequest() in that case.

endRequest();

}

//......

}

//......

}

這里的service方法在getErrorState().isError()為false的時候,會調用adapter的service方法

CoyoteAdapter

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/connector/CoyoteAdapter.java

@Override

public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)

throws Exception {

Request request = (Request) req.getNote(ADAPTER_NOTES);

Response response = (Response) res.getNote(ADAPTER_NOTES);

//...

try {

// Parse and set Catalina and configuration specific

// request parameters

postParseSuccess = postParseRequest(req, request, res, response);

if (postParseSuccess) {

//check valves if we support async

request.setAsyncSupported(

connector.getService().getContainer().getPipeline().isAsyncSupported());

// Calling the container

connector.getService().getContainer().getPipeline().getFirst().invoke(

request, response);

}

if (request.isAsync()) {

async = true;

ReadListener readListener = req.getReadListener();

if (readListener != null && request.isFinished()) {

// Possible the all data may have been read during service()

// method so this needs to be checked here

ClassLoader oldCL = null;

try {

oldCL = request.getContext().bind(false, null);

if (req.sendAllDataReadEvent()) {

req.getReadListener().onAllDataRead();

}

} finally {

request.getContext().unbind(false, oldCL);

}

}

Throwable throwable =

(Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

// If an async request was started, is not going to end once

// this container thread finishes and an error occurred, trigger

// the async error process

if (!request.isAsyncCompleting() && throwable != null) {

request.getAsyncContextInternal().setErrorState(throwable, true);

}

} else {

request.finishRequest();

response.finishResponse();

}

} catch (IOException e) {

// Ignore

} finally {

//......

// Recycle the wrapper request and response

if (!async) {

request.recycle();

response.recycle();

}

}

}

會在finally里頭調用request.recycle()

Request#recycle

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/connector/Request.java

里頭的方法會調用recycleSessionInfo

protected void recycleSessionInfo() {

if (session != null) {

try {

session.endAccess();

} catch (Throwable t) {

ExceptionUtils.handleThrowable(t);

log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t);

}

}

session = null;

requestedSessionCookie = false;

requestedSessionId = null;

requestedSessionURL = false;

requestedSessionSSL = false;

}

這里就更新了兩個事件

forward中更新

適合處理error直接forward的情況,比如鑒權不通過,直接forward的,這個時候還沒進入到servlet的service方法

ApplicationDispatcher#recycleRequestWrapper

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/core/ApplicationDispatcher.java

private void invoke(ServletRequest request, ServletResponse response,

State state) throws IOException, ServletException {

//......

// Get the FilterChain Here

ApplicationFilterChain filterChain =

ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

// Call the service() method for the allocated servlet instance

try {

// for includes/forwards

if ((servlet != null) && (filterChain != null)) {

filterChain.doFilter(request, response);

}

// Servlet Service Method is called by the FilterChain

} catch (ClientAbortException e) {

ioException = e;

} catch (IOException e) {

wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",

wrapper.getName()), e);

ioException = e;

} catch (UnavailableException e) {

wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",

wrapper.getName()), e);

servletException = e;

wrapper.unavailable(e);

} catch (ServletException e) {

Throwable rootCause = StandardWrapper.getRootCause(e);

if (!(rootCause instanceof ClientAbortException)) {

wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",

wrapper.getName()), rootCause);

}

servletException = e;

} catch (RuntimeException e) {

wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",

wrapper.getName()), e);

runtimeException = e;

}

// Release the filter chain (if any) for this request

try {

if (filterChain != null)

filterChain.release();

} catch (Throwable e) {

ExceptionUtils.handleThrowable(e);

wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters",

wrapper.getName()), e);

// FIXME: Exception handling needs to be similar to what is in the StandardWrapperValue

}

// Deallocate the allocated servlet instance

try {

if (servlet != null) {

wrapper.deallocate(servlet);

}

} catch (ServletException e) {

wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",

wrapper.getName()), e);

servletException = e;

} catch (Throwable e) {

ExceptionUtils.handleThrowable(e);

wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",

wrapper.getName()), e);

servletException = new ServletException

(sm.getString("applicationDispatcher.deallocateException",

wrapper.getName()), e);

}

// Reset the old context class loader

context.unbind(false, oldCCL);

// Unwrap request/response if needed

// See Bugzilla 30949

unwrapRequest(state);

unwrapResponse(state);

// Recycle request if necessary (also BZ 30949)

recycleRequestWrapper(state);

// ......

}

執行完servlet之后(不管成功還是失敗),會調用recycleRequestWrapper

private void recycleRequestWrapper(State state) {

if (state.wrapRequest instanceof ApplicationHttpRequest) {

((ApplicationHttpRequest) state.wrapRequest).recycle(); }

}

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/core/ApplicationHttpRequest.java

/**

* Recycle this request

*/

public void recycle() {

if (session != null) {

session.endAccess();

}

}

這里會調用endAccess,更新兩個時間

小結

每次的請求,都會跟新session的lastAccessedTime和thisAccessedTime,只有沒有訪問超過設定時間才會失效

server.session.timeout設定的單位是秒,但是小于60的話,會被重置為60,內部轉為分鐘單位來算,默認1800是30分鐘

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/394117.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/394117.shtml
英文地址,請注明出處:http://en.pswp.cn/news/394117.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

javascript控制臺_如何使用JavaScript控制臺改善工作流程

javascript控制臺by Riccardo Canella里卡多卡內拉(Riccardo Canella) 如何使用JavaScript控制臺改善工作流程 (How you can improve your workflow using the JavaScript console) As a web developer, you know very well the need to debug your code. We often use extern…

appium===setup/setupclass的區別,以及@classmathod的使用方法

一、裝飾器 1.用setUp與setUpClass區別 setup():每個測試case運行前運行 teardown():每個測試case運行完后執行 setUpClass():必須使用classmethod 裝飾器,所有case運行前只運行一次 tearDownClass():必須使用classmethod裝飾器,所有case運行完后只運行一次 2.是修飾符&#xf…

cache failed module status_Flutter混編之路——iOS踩坑記錄

一、運行Xcode編譯或者flutter run/build 過程中報錯:"x86_64" is not an allowed value for option "ios-arch".解決方案在Debug.xcconfig中指定 “FLUTTER_BUILD_MODEdebug”,Release.xcconfig中指定“FLUTTER_BUILD_MODErelease”…

【最短路徑Floyd算法詳解推導過程】看完這篇,你還能不懂Floyd算法?還不會?...

簡介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一種利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的算法,與Dijkstra算法類似。該算法名稱以創始人之一、1978年圖靈獎獲得者、斯坦福大學計算機科學系教授羅伯特…

java object類的常用子類_Java中Object類常用的12個方法,你用過幾個?

前言Java 中的 Object 方法在面試中是一個非常高頻的點,畢竟 Object 是所有類的“老祖宗”。Java 中所有的類都有一個共同的祖先 Object 類,子類都會繼承所有 Object 類中的 public 方法。先看下 Object 的類結構(快捷鍵:alt7):1.…

leetcode面試題 04.12. 求和路徑(dfs)

給定一棵二叉樹,其中每個節點都含有一個整數數值(該值或正或負)。設計一個算法,打印節點數值總和等于某個給定值的所有路徑的數量。注意,路徑不一定非得從二叉樹的根節點或葉節點開始或結束,但是其方向必須向下(只能從父節點指向子…

javaweb學習總結(二十二)——基于Servlet+JSP+JavaBean開發模式的用戶登錄注冊

一、ServletJSPJavaBean開發模式(MVC)介紹 ServletJSPJavaBean模式(MVC)適合開發復雜的web應用,在這種模式下,servlet負責處理用戶請求,jsp負責數據顯示,javabean負責封裝數據。 ServletJSPJavaBean模式程序各個模塊之間層次清晰&…

2018黃河獎設計大賽獲獎_宣布我們的freeCodeCamp 2018杰出貢獻者獎獲獎者

2018黃河獎設計大賽獲獎by Quincy Larson昆西拉爾森(Quincy Larson) 宣布我們的freeCodeCamp 2018杰出貢獻者獎獲獎者 (Announcing Our freeCodeCamp 2018 Top Contributor Award Winners) Over the past 3 years, freeCodeCamp.org has grown from a small open source proje…

Log4j配置詳解

來自: http://www.blogjava.net/zJun/archive/2006/06/28/55511.html Log4J的配置文件(Configuration File)就是用來設置記錄器的級別、存放器和布局的,它可接keyvalue格式的設置或xml格式的設置信息。通過配置,可以創建出Log4J的運行環境。1. 配置文件 …

cors數據類型_如何根據RTK的差分格式選擇千尋cors賬號的源節點進行設置?

千尋cors賬號的設置中源節點是根據使用的品牌RTK是為雙星儀器還是三星儀器選擇,但問題就在于我們看到的RTK的技術參數中一般很少見到標注儀器的衛星系統,更多的是差分格式。其實千尋cors賬號的源節點也可以根據RTK的差分格式進行選擇,不過這兩…

java swing 串口_ComTest 接收串口數據,并顯示在文本框內,通過JavaSwing實現 Develop 265萬源代碼下載- www.pudn.com...

文件名稱: ComTest下載 收藏√ [5 4 3 2 1 ]開發工具: Java文件大小: 3157 KB上傳時間: 2016-09-21下載次數: 0提 供 者: 韓坤詳細說明:接收串口數據,并顯示在文本框內,通過JavaSwing實現-Receive serial data, and displayed in the t…

leetcode329. 矩陣中的最長遞增路徑(dfs)

給定一個整數矩陣,找出最長遞增路徑的長度。對于每個單元格,你可以往上,下,左,右四個方向移動。 你不能在對角線方向上移動或移動到邊界外(即不允許環繞)。示例 1:輸入: nums [[9,9,4],[6,6,8…

SQL大圣之路筆記——PowerDesigner之新建table、view、proc

1. 新建table、view、proc 轉載于:https://www.cnblogs.com/allenzhang/p/6305564.html

用python繪制一條直線_python繪制直線的方法

本文實例為大家分享了python繪制直線的具體代碼&#xff0c;供大家參考&#xff0c;具體內容如下#!/usr/bin/env pythonimport vtk# 繪制通用方法def myshow(linepolydata):# Now well look at it.lineMapper vtk.vtkPolyDataMapper()if vtk.VTK_MAJOR_VERSION < 5:lineMap…

測試驅動開發 測試前移_我如何以及為什么認為測試驅動開發值得我花時間

測試驅動開發 測試前移by Ronauli Silva通過羅納利席爾瓦(Ronauli Silva) I first read about test driven development (TDD) in some technical reviews blog, but I barely read it (or thought about it). Why would people write tests first when they already knew the…

P2921 [USACO08DEC]在農場萬圣節Trick or Treat on the Farm

對于一個牛&#xff0c;它存在兩種狀態&#xff1a;1.處于聯通分量 2.不處于聯通分量。對于處于聯通分量的牛&#xff0c;求出聯通分量的大小&#xff1b;對于不處于聯通分量的牛&#xff0c;求出其距離聯通分量的路程聯通分量大小。 不同的聯通分量&#xff0c;染上不同的顏色…

ASP.NET MVC5+EF6+EasyUI 后臺管理系統(1)-前言與目錄(持續更新中...)

開發工具&#xff1a;VS2015(2012以上)SQL2008R2以上數據庫 您可以有償獲取一份最新源碼聯系QQ:729994997 價格 666RMB 升級后界面效果如下&#xff1a; 日程管理 http://www.cnblogs.com/ymnets/p/7094914.html 任務調度系統界面 http://www.cnblogs.com/ymnets/p/5065154.h…

leetcode106. 從中序與后序遍歷序列構造二叉樹(dfs)

根據一棵樹的中序遍歷與后序遍歷構造二叉樹。注意: 你可以假設樹中沒有重復的元素。例如&#xff0c;給出中序遍歷 inorder [9,3,15,20,7] 后序遍歷 postorder [9,15,7,20,3] 返回如下的二叉樹&#xff1a;3/ \9 20/ \15 7解題思路 根據后序遍歷的最后一個元素是父節點&…

【FRDM-K64F學習筆記】使用ARM mbed和Keil MDK下載你的第一個程序

FRDM-K64F開發平臺采用MK64FN1M0VLL12微控制器。該控制器包含一個帶有浮點單元的ARM Cortex-M4內核。其最高工作頻率為120MHz&#xff0c;具有256KB的RAM、1MB閃存以及許多其他外設。它非常適合大多數可以采用以太網、SD卡存儲以及板載模擬-數字轉換器的IoT應用。但是&#xff…

php 實時更新內容_億級視頻內容如何實時更新?優酷視頻背后的技術揭秘

簡介&#xff1a; 優酷視頻內容數據天然呈現巨大的網絡結構&#xff0c;各類數據實體連接形成了數十億頂點和百億條邊的數據量&#xff0c;面對巨大的數據量&#xff0c;傳統關系型數據庫往往難以處理和管理&#xff0c;圖數據結構更加貼合優酷的業務場景&#xff0c;圖組織使用…