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

上面的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进行赋值操作,一旦赋值,当高并发时,线程问题是必然的

  1. private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
  2. throws Exception {
  3.  
  4. while (!this.modelMethods.isEmpty()) {
  5. InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
  6. ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
  7. if (container.containsAttribute(ann.name())) {
  8. if (!ann.binding()) {
  9. container.setBindingDisabled(ann.name());
  10. }
  11. continue;
  12. }
  13.  
  14. Object returnValue = modelMethod.invokeForRequest(request, container);
  15. if (!modelMethod.isVoid()){
  16. String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
  17. if (!ann.binding()) {
  18. container.setBindingDisabled(returnValueName);
  19. }
  20. if (!container.containsAttribute(returnValueName)) {
  21. container.addAttribute(returnValueName, returnValue);
  22. }
  23. }
  24. }
  25. }

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

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

  1. public abstract class BaseController {
  2.  
  3. @Autowired
  4. protected HttpServletRequest request;
  5. @Autowired
  6. protected HttpServletResponse response;
  7. }

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

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

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

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

  1. @RequestMapping(value = "/cms/preview/{id}",method = RequestMethod.GET)
  2.  
  3. public void preview(HttpServletResponse response, @PathVariable("id") String id) {
  4.  
  5. }

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

解决方案:

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

改动:

1  增加了@Autowired

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

  1. public class SuperBaseController {
  2. @Autowired
  3. protected HttpServletRequest request;
  4. @Autowired
  5. protected HttpServletResponse response;
  6. private SysUser curUser;
  7. @Value("${isDebug}")
  8. protected Boolean isDebug;
  9.  
  10. @ModelAttribute
  11. public void setLang(HttpServletRequest request, HttpServletResponse response) {
  12. this.sysHostUrl = this.request.getAttribute(ComContants.SYSHOSTURL).toString();
  13. this.sysHost = this.request.getAttribute(ComContants.SYSHOST).toString();
  14. }
  15.  
  16. public SysUser getCurUser() {
  17. curUser=WebUtil.getCurrentUser(isDebug, request);
  18. return curUser;
  19. }
  20.  
  21. }

转自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. iOS9新框架—Watch Connectivity(详情:http://ios.itcast.cn/subject/ios9/index.shtml )

    1背景. Watch Connectivity--专为用来实现Watch与配对iPhone上的文件和数据的来回传输而生. 2.iOS8与iOS9发送数据的对比. 我们知道数据交换在iOS8中就有,我们 ...

  2. 告诉你一些DBA求职面试技巧

    告诉你一些DBA求职面试技巧 要自信!永远不要低估你的能力.如果你不了解什么问题的答案,承认它.重点放在你找出答案的能力和你学习的意愿. 不要自大!是的,你可能过于自信而被认为是骄傲的.轻率的,甚至是 ...

  3. Shell命令-用户用户组管理之id、su

    文件及内容处理 - id.su 1. id:查看用户的uid,gid及归属的用户组 id命令的功能说明 id 命令用于显示用户的 ID,以及所属群组的 ID.id 会显示用户以及所属群组的实际与有效I ...

  4. C学习笔记(1)---数据类型,变量,储存类

    1.常用基本数据类型占用空间(64位机器为例): char : 1个字节 -- int :4个字节 -- float:4个字节 -- double:8个字节 2.书写类型: A.整数: a. 默认为1 ...

  5. 初学JavaScript正则表达式(九)

    分组:可以用 ( ) 来进行分组 一.Byron重复三次             Byron{3} --------- Byronnn 只是将紧挨着量词的字符重复            (Byron) ...

  6. ubuntu系统中查看python模块的源码

    案例:查看multiprocessing模块源码 1. 进入交互模式,导入模块,以multiprocessing模块为例 2. 查看multiprocessing.__file__属性,找到该模块的源 ...

  7. java.net.URL类

    package com.mozq.boot.kuayu01.demo; import java.net.MalformedURLException; import java.net.URL; publ ...

  8. JAVA多线程间隔时间段执行方法

    import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class ManyProject ...

  9. hdu 6495 dp

    http://acm.hdu.edu.cn/showproblem.php?pid=6495 题意 有n个挑战(1e3),假如接受,在挑战之前体力x会变成min(x,\(b[i]\)),然后会减去a[ ...

  10. SLAM中的非线性优化

    总结一下SLAM中关于非线性优化的知识. 先列出参考: http://jacoxu.com/jacobian%E7%9F%A9%E9%98%B5%E5%92%8Chessian%E7%9F%A9%E9 ...