Springmvc获取request对象&线程安全

概述:
在使用Springmvc开发web系统时,经常要用到request对象来处理请求,比如获取客户端IP地址、请求的url、header中的属性(cookie、授权信息等)、body中的数据等。由于Springmvc中的Controller、Service等都是单例的,因此就需要关注request对象是否是线程安全的:当有大量并发请求时,能否保证不同请求/线程中使用不同的request对象。
(本文对request的讨论,同样适用于response对象、InputStream/Reader、OutputStream/Writer等)

测试线程安全性的方法:
基本思路:模拟客户端大量并发请求,然后在服务器判断这些请求是否使用了相同的request对象。
判断request对象是否相同,最直观的方式是打印出request对象的地址。然而,几乎所有的web服务器实现中都使用了线程池,这就导致了先后到达的两个请求,可能由同一个线程处理:在前一个请求处理完成后,线程池回收该线程,并将该线程重新分配给后面的请求;而在同一线程中,使用的request对象很可能是同一个(地址相同,属性不同),因此,即便是对于线程安全的方法,不同的请求使用的request对象地址也可能相同。在这里,使用request中的请求参数作为request是否相同的依据。

获取request的方法:
方法1,Controller方法中加参数:
分析:在Controller方法开始处理请求时,Spring会将request对象赋值到方法参数中。此时request对象是方法参数,相当于是局部变量,一定是线程安全的。
缺点:
(1)如果多个controller方法中都需要request对象,那么在每个方法中都需要添加一遍request参数;
(2)request对象的获取只能从controller开始,如果使用request对象的地方在函数调用层级比较深的地方,那么整个调用链上的所有方法都需要添加request参数。
(实际上,除了定时器等特殊情况,request相当于线程内部的一个全局变量,而该方法相当于将一个全局变量传来传去)

方法2,自动注入:
@Autowired
private HttpServletRequest request;
分析:在Springmvc中,Controller是单例的,但是其中注入的request却是线程安全的,因为在这种方式中,Controller初始化时并没有注入一个request对象,而是注入了一个代理proxy,当Controller中需要使用request对象时,通过代理获取request对象(url中有源码解释,最终request是线程局部变量(ThreadLocal),是线程安全的)。
优点:
(1)注入不局限于Controller中,在Service、Repository、普通Bean中都可以注入;
(2)注入对象不局限于request,并保证线程安全;
(3)减少代码冗余。
(不过,如果web系统中有很多controller,每个controller中都会使用request对象(实际上这很常见),这时就需要写很多次注入request的代码,如果再加上response,代码就更繁琐了)

方法3,基类中自动注入:
分析:当创建不同的派生类对象时,基类中的域在不同的派生类对象中会占据不同的内存空间,也就是说将注入request的代码放在基类中对线程安全没有任何影响。
优缺点:
(1)与方法2相比,避免了在不同的Controller中重复注入request,但考虑到Java只允许继承一个基类,所以如果Controller需要继承其它类时,该方法不再好用;
(2)无论方法2还是方法3,都只能在Bean中注入request,如果其它方法(如工具类中的static方法)需要使用request对象,依然需要在调用这些方法时将request参数传进去。

方法4:手动调用:
HttpServletRequest request = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest();
分析:该方法与方法2类似,只不过方法2通过自动注入实现,本方法使用手动调用,线程安全。
优点:可以在非Bean中直接获取;
缺点:代码繁琐,可以与其它方法配合使用

方法5:@ModelAttribute方法:
@ModelAttribute
public void bindRequest(HttpServletRequest request) {
    this.request = request;
}
分析:虽然request本身是线程安全的,但是Controller是单例的,request作为单例的一个域,无法保证线程安全。

总结:
除了方法5,方法1-4都是线程安全的。如果系统中request对象使用较少,哪种方式均可;如果使用较多,建议使用方法2/3来减少代码冗余,如果需要在非Bean对象中使用request,既可以通过参数传入,也可以直接在方法中通过手动调用获得。

原文地址:https://www.cnblogs.com/yuanfei1110111/p/10137003.html

时间: 2024-08-07 14:27:22

Springmvc获取request对象&线程安全的相关文章

springMVC获取request对象

方法一: @Autowired private HttpServletRequest request; 方法二: public void test( HttpServletRequest request,HttpServletReponse reponse){ } 方法三:加入监听器 1,在web.xml 配置如下 <listener> <listener-class> org.springframework.web.context.request.RequestContextLi

springmvc中获取request对象,加载biz(service)的方法

获取request对象: 首先配置web.xml文件--> [html] view plaincopy <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> 然后在程序中获取: 代码: [java] view plaincopy HttpServletRequest 

在SpringMVC中获取request对象的几种方式

1.最简单的方式(注解法) 1 2 @Autowired private  HttpServletRequest request; 2.最麻烦的方法 a. 在web.xml中配置一个监听 <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> b.之后在程序里可以用 Http

在SpringMVC中获取request对象

1.注解法 Java代码   @Autowired private  HttpServletRequest request; 2. 在web.xml中配置一个监听 Xml代码   <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> 之后在程序里可以用 Java代码   H

如何在SpringMVC中获取request对象

1.注解法 @Autowired private HttpServletRequest request; 2. 在web.xml中配置一个监听 HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); 3.直接在参数中引入 public String hello(HttpServletRequest request,HttpS

java webservice服务器端获取request对象的三种方式

有的时候在webservice里我们需要获取request对象和response对象,比如想要获得客户端的访问ip的时候就需要这么做,下面说三种方式,当然三种方式可能是针对不同方式部署webservice获取request对象的方法. 第一种:先配置注入: @Resource private WebServiceContext webServiceContext; 其次是下面的代码: MessageContext mc = webServiceContext.getMessageContext(

Struts2,springMVC获取request和response

springMVC获取request和response1:在BaseController中加入: protected HttpServletRequest request;   protected HttpServletResponse response;   protected HttpSession session; @ModelAttribute   public void setReqAndRes(HttpServletRequest request, HttpServletRespon

Spring Mvc 在非controller层 实现获取request对象

一般我们在Controller层,会编写类似这样的方法 @Controller @RequestMapping(value="/detail") public class GetURIDetailController { @SystemControllerLog(description = "id") @RequestMapping(value="/{id}",method={RequestMethod.GET}) public ModelAnd

springMVC 获取request 处理全局session业务

<a target=_blank href="http://blog.csdn.net/is_zhoufeng/article/details/7559756" style="color: rgb(0, 0, 0); text-decoration: none; font-family: 'Microsoft YaHei'; font-size: 20px; line-height: 30px; ">springMVC中得到request对象,sessi