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分钟
java forward 修改请求参数_聊聊springboot session timeout参数设置相关推荐
- boot spring 对参数检测_【springboot】@Valid参数校验
转自: https://blog.csdn.net/cp026la/article/details/86495659 扯淡: 刚开始写代码的时候对参数的校验要么不做.要么写很多类似 if( xx == ...
- 查看java运行时参数_查看JVM运行时参数
1.查看JVM运行时参数 -XX:+PrintFlagsInitial -XX:PrintFlagsFinal -XX:+UnlockExperimentalVMOptions 解锁实验参数 -XX: ...
- java gc调优常用参数_常用JVM调优参数
JVM调优有许多参数优化,下面整理了一些我自己能够理解的参数 -XX:AutoBoxCacheMax -XX:+AlwaysPreTouch CMSInitiatingOccupancyFractio ...
- db2自定义函数能返回几个参数_函数的定义、参数、返回值
一.昨日内容回顾 昨日内容回顾 其他模式补充 r+ w+ a+ 文件内光标移动 在rt模式下read内n表示的读取字符的个数 其他情况及其他方法内n表示都是字节数 f.read(n) f.seek(o ...
- httpurlconnect设置中文参数_数控三菱CNC机床参数的设置及报警解除!
数控三菱CNC的硬件连接检查与设置执行完毕向系统送电后,显示器上的READY绿灯仍然不亮.而且在[诊断]――[报警] 画面上显示很多报警内容,哪些是开机时必须设置的呢?又如何解除故障报警呢? 1.开机 ...
- mysql函数输出参数_函数--返回值、参数和作用域
一.函数的返回值--return的作用 1.return将return后面的值作为函数的输出返回值,当函数被调用时,返回值可以被其他变量接收.使用. 而print只是打印在控制台,一个函数如果没有re ...
- java懒加载注解_在springboot中实现个别bean懒加载的操作
懒加载---就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中. @Lazy 在需要懒加载的bean上加上@Lazy ...
- java财务对账系统设计_聊聊对账系统的设计方案
前言 对账系统作为支付系统中的基石系统,处于整个支付环节中的最后一层,主要用来保证我方支付数据与第三方支付渠道或银行的数据一致性. 在没有对账系统之前,财务在第二日手工核对前一日的应收与实收.倘若不一 ...
- java websocket修改为同步_初级Java程序员需要掌握哪些主流技术才能拿25K?
某天,小五看到小丽愁眉苦脸的,于是问了她有什么心事~ 公司的社区网站访问越来越慢了,特别是搜索功能,这该怎么优化呀? 你们都用了啥技术搭建的呀? springboot+mybatis,数据库mysql ...
最新文章
- Oracle中不同条件的日期查询
- V-1-2 登陆ESXi服务器
- LeetCode OJ:Pascal's TriangleII(帕斯卡三角II)
- python函数应用_Python 函数及其应用
- 关于JAP FetchType.LAZY(hibernate实现)的理解
- AUTOSAR专业知识篇(七)-比亚迪汉ECU接口
- Django中--使用redis存储历史浏览记录
- error_reporting()的用法
- 众说纷纭的ul、ol、li
- 机器学习算法基础3-sklearn数据集与估计器
- Yii Framework2.0开发教程(2)使用表单Form
- 解决域用户安装软件权限问题
- 差分编码解析以及FPGA实现
- Kibana 操作 Elasticsearch
- bugzilla mysql_使用Mysql 5.6.11安装Bugzilla 4.2.5
- bzoj1898: [Zjoi2004]Swamp 沼泽鳄鱼
- 如何将ppt改为无法修改的pdf
- j2me专业手机游戏开发基础
- 初创企业购买企业邮箱_停止对初创企业的限制
- 【网易实习准备】往年笔试题目练习
热门文章
- 2 文件处理、权限管理、搜索
- Python - 排序( 插入, 冒泡, 快速, 二分 )
- Java学习进阶—高级编程
- 图嵌入综述 (arxiv 1709.07604) 译文五、六、七
- 区块链监管的一年,剥离“币”的区块链技术该何去何从?
- Python基础-----列表、元组、集合(2)
- dataTables插件使用
- secilog 1.17 发布 增加了英文版本等新功能
- cardsui-for-android
- C#中的事件和委托(续)