zoukankan      html  css  js  c++  java
  • springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题

    最近在使用公司之前的springMVC框架,在测试过程中发现了一个很奇怪的现象;在同时访问下并且这时后台返回较慢时,系统报session为空值或者是数据显示别人的数据。这时查找了业务代码的逻辑,并没有任何问题。此时问题肯定出现在框架里,经过根据调试。发现程序中运用了ThreadLocal类来存储session数据,赶紧学习下这个ThreadLocal类  发现

    ThreadLocal利用线程作为key,自己为value

    在线程池中线程是重复利用的,如果你不在请求执行完毕后清除它,危险可想而知!

    1、更改自己的资料时发现更改到了别人的资料

    2、未登录也可以操纵一下需要权限的操作

    3、无缘无故登录到了别人的账号(串号?)

    SpringMVC也是使用线程池来进行业务处理,所以我们需要在使用完时清理掉ThreadLocal

    清理办法:

    可以使用拦截器覆盖postHandle(响应时处理)调用ThreadLocal.remove

    我满心 欢喜提交上线时,发现还是会出现这种情况。又各种调试,更大的坑被发现了;产生的问题如下代码

    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对象,这样基类继承该类,想要获取对象直接可以拿到,虽然这样很简便,但是出现了更为严重的问题。我们都知道SpringMVC控制层是单例的,这里会产生线程不安全问题,在并发量大的情况下,获取的对象可能是同一个对象,或者为null,这些都是并发造成的问题

    分析:

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

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

    解决方法

    一, 可以使用其他两种方式来获取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就明白了 

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

     @RequestMapping(value = "/cms/preview/{id}",method = RequestMethod.GET)
     
        public void preview(HttpServletResponse response, @PathVariable("id") String id) {
     
        }
  • 相关阅读:
    以下文件中的行尾不一致。要将行尾标准化吗
    用户 NT AUTHORITYNETWORK SERVICE 登录失败
    sql server 2008 不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法
    附加数据库对于服务器失败(Microsoft.SqlServer.Smo),无法升级数据库,因为它是只读的,或者具有只读文件
    IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法
    HTTP 错误 404.2
    vs智能提示突然消失的解决办法 (vs2008 vs2010 vs2012 智能提示)
    Visual Studio 常用快捷键
    403.14-Forbidden Web 服务器被配置为不列出此目录的内容及Login on failed for "IIS APPPOOLASP.NET v4.0"问题
    短信轰炸PC版
  • 原文地址:https://www.cnblogs.com/hhwww/p/14052430.html
Copyright © 2011-2022 走看看