1. springmvc在获取Request和Response有很多方式:具体请看:https://www.cnblogs.com/wade-luffy/p/8867144.html
  2. 产生线程问题的代码如下:
public class BaseController {
protected HttpServletRequest request; protected HttpServletResponse response; protected HttpSession session; @ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; this.session = request.getSession(); }
}

上面的BaseController中使用ModelAttribute注解来获取request和response对象,这样基类继承该类,想要获取对象直接可以拿到,虽然这样很简便,但是这里会产生线程不安全问题,在并发量大的情况下,获取的对象可能是同一个对象,或者为null,这些都是并发造成的问题

分析:

1 . ModelAttribute注解有以下三个作用:
–1)有此注解的方法会在每一个请求前执行,也就是controller执行你请求的方法之前
–2)有此注解的参数,会从前端提交的表单中获取数据(现在一般不使用,因为不使用也可以获取到)
–3)有此注解的方法的返回值,可以直接在spring的view中使用(也可以在BaseContoller中添加方法,传入参数 Model model,spring会自动注入model参数,给这个model添加值,也可在view中使用)

2 . SpringMVC会优先执行被@ModelAttribute注解的方法。也就是说我们每一次请求,都会去调用init()方法,进行初始化操作,那么就会对request,response,httpSession进行赋值操作,一旦赋值,当高并发时,线程问题是必然的

 private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
throws Exception { while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
if (container.containsAttribute(ann.name())) {
if (!ann.binding()) {
container.setBindingDisabled(ann.name());
}
continue;
} Object returnValue = modelMethod.invokeForRequest(request, container);
if (!modelMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!ann.binding()) {
container.setBindingDisabled(returnValueName);
}
if (!container.containsAttribute(returnValueName)) {
container.addAttribute(returnValueName, returnValue);
}
}
}
}

一, 可以使用其他两种方式来获取request和response对象

1: 使用@Autowired或者@Resource注解注入,

public abstract class BaseController {

    @Autowired
protected HttpServletRequest request;
@Autowired
protected HttpServletResponse response;
}

使用@Autowired或者@Resource注解注入,是线程安全的,当用户发出请求后,会经过FrameworkServlet中的processRequest()方法做了一些骚操作,然后再交给子类DispatcherServlet中的doService()去处理这个请求。这些骚操作就包括把request,response对象包装成ServletRequestAttributes对象,然后放入到ThreadLocal中,看到ThreadLocal就明白了

    private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes"); private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
new NamedInheritableThreadLocal<RequestAttributes>("Request context");
    private static ServletRequestAttributes currentRequestAttributes() {
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
if (!(requestAttr instanceof ServletRequestAttributes)) {
throw new IllegalStateException("Current request is not a servlet request");
}
return (ServletRequestAttributes) requestAttr;
}

Autowired注入流程结合上面代码:@Autowired注入HttpServletRequest对象的过程。这里以HttpServletRequest对象注入举例。首先调用DefaultListableBeanFactory中的findAutowireCandidates()方法,判断autowiringType类型是否和requiredType类型一致或者是autowiringType是否是requiredType的父接口(父类)。如果满足条件的话,我们会从resolvableDependencies中通过autowiringType(对应着上文的ServletRequest)拿到autowiringValue(对应着上文的RequestObjectFactory)。然后调用AutowireUtils.resolveAutowiringValue()对我们的ObjectFactory进行处理。

二, 简单粗暴不会产生任何问题:直接在需要request和response对象得方法参数注入即可,有其他参数直接接着在后面写,即可,这个方法参数,作用域在方法,不会产生线程问题

 @RequestMapping(value = "/cms/preview/{id}",method = RequestMethod.GET)

    public void preview(HttpServletResponse response, @PathVariable("id") String id) {

    }

具体详细请看:https://blog.csdn.net/weixin_33768481/article/details/88303335
里面也介绍了进行压力测试模拟高并发请求

解决方案:

现在改成如下代码,则是可以的!

改动:

1  增加了@Autowired

2 设置curUser为private,并且封装成属性:getCurUser()

public class SuperBaseController {
@Autowired
protected HttpServletRequest request;
@Autowired
protected HttpServletResponse response;
private SysUser curUser;
@Value("${isDebug}")
protected Boolean isDebug; @ModelAttribute
public void setLang(HttpServletRequest request, HttpServletResponse response) {
this.sysHostUrl = this.request.getAttribute(ComContants.SYSHOSTURL).toString();
this.sysHost = this.request.getAttribute(ComContants.SYSHOST).toString();
} public SysUser getCurUser() {
curUser=WebUtil.getCurrentUser(isDebug, request);
return curUser;
} }

转自1:https://blog.csdn.net/hanjun0612/article/details/103421903

转自2: https://blog.csdn.net/hanjun0612/article/details/103427040

springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题(转)的更多相关文章

  1. Struts2,springMVC获取request和response

    springMVC获取request和response1:在BaseController中加入: protected HttpServletRequest request;   protected H ...

  2. 在springMVC的controller中获取request,response对象的一个方法

    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttr ...

  3. springMVC中获取request和response对象的几种方式(RequestContextHolder)

    springMVC中获取request和response对象的几种方式 1.最简单方式:参数 2.加入监听器,然后在代码里面获取 原文链接:https://blog.csdn.net/weixin_4 ...

  4. SpringMvc4中获取request、response对象的方法

    springMVC4中获取request和response对象有以下两种简单易用的方法: 1.在control层获取 在control层中获取HttpServletRequest和HttpServle ...

  5. struts2中获取request、response,与android客户端进行交互(文件传递给客户端)

    用struts2作为服务器框架,与android客户端进行交互需要得到request.response对象. struts2中获取request.response有两种方法. 第一种:利用Servle ...

  6. spring MVC中获取request和response:

    spring MVC中获取request和response: HttpServletRequest request = ((ServletRequestAttributes) RequestConte ...

  7. Spring 手动获取request和response

    //获取responseHttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getReque ...

  8. RequestContextHolder获取request和response

    RequestContextHolder获取request和response 2019年03月16日 15:18:15 whp404 阅读数:21更多 个人分类: Spring   首先需要在web. ...

  9. springMVC获取request和response

    转载:http://blog.sina.com.cn/s/blog_7085382f0102v9jg.html 1.参数 例如: @RequestMapping("/test") ...

随机推荐

  1. 关于解决Xcode更新7.3之后插件不能用的问题

    Xcode更新7.3之后,之前安装好好的插件现在突然间不能用了(如:我在写背景颜色或者字体颜色的时候,突然间不出来联想的图案来供我选择了),解决这个问题的步骤如下: 1.打开电脑终端,把default ...

  2. Python之Beautiful Soup 4使用实例

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航.查找.修改文档的方式.Beautiful Soup 4 官方文档: ...

  3. mac上安装npm

    检查brew -v是否安装了homebrew这个macOS 缺失的软件包的管理器.如果安装,跳转到第3步,否则跳转到第二步: 安装homebrew.安装跳转到官网指导.等待安装好之后,输入brew - ...

  4. mssql sqlserver sql脚本自动遍历重复生成指定表记录

    摘要: 今天接到老板的需求,需根据一张表中列值,自动重复表中的数据行,然后显示给用户 实验环境:sqlserver 2008 R2 转自:http://www.maomao365.com/?p=841 ...

  5. 使用vs code编写Markdown文档以及markdown语法详解

    首先安装vscode工具,下载地址如下: https://code.visualstudio.com/ 在vs code的扩展中安装: Markdown Preview Enhanced 这款插件,安 ...

  6. [视频教程] 配置vscode的PHP自动补全提示与使用Xdebug进行远程调试debug

    默认下载安装完的vscode并不能准确提示和检测PHP的语法错误,需要手动指定一下本机的PHP程序路径.按下面的操作配置完后就能在文件保存的时候检测语法有无错误.打开文件->首选项->se ...

  7. 1. 配置Java开发环境

    一.JDK & JRE & JVM 1. JDK是什么? JDK的全称是Java SE Development Kit,即Java标准版开发包,是Oracle提供的一套用于开发Java ...

  8. golang数据结构和算法之StackArray数组堆栈

    用数组实现的堆栈, 另一种,是用链表实现的堆栈, 在各种不同的编程语言上, 实现都是类似的. StackArray.go package StackArray //基于数组实现的堆栈 const ar ...

  9. JPA简介

    JPA的学习 JPA是Java Persistence API的简称,中文名Java持久层API.是Java EE5.0平台中Sun为了统一持久层ORM框架而制定的一套标准,注意是一套标准,而不是具体 ...

  10. appium--使用PyYAML封装Capability

    前戏 YAML 语言的设计目标,就是方便人类读写.它实质上是一种通用的数据串行化格式. 它的基本语法规则如下. YAML大小写敏感: 使用缩进代表层级关系: 缩进只能使用空格,不能使用TAB,不要求空 ...