Spring中获取request的几种方法

  • 时间:
  • 浏览:0

减少代码冗余:只可不能能 在可不能能 request对象的Bean中注入request对象,便还可不能能在该Bean的各个依据中使用,与依据1相比大大减少了代码冗余。

image

https://stackoverflow.com/questions/22674044/inject-httpservletrequest-into-controller

线程安全性

https://docs.spring.io/spring/docs/4.1.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection

本文将介绍在Spring MVC开发的web系统中,获取request对象的几种依据,并讨论其线程安全性。

注入的对象不限于request:除了注入request对象,该依据还还可不能能注入有些scope为request或session的对象,如response对象、session对象等;并保证线程安全。

https://stackoverflow.com/questions/10541934/spring-aop-and-aspect-thread-safety-for-an-autowired-httpservletrequest-bean

测试结果:线程安全

代码示例

判断request对象有无相同,最直观的依据是打印出request对象的地址,机会相同则说明使用了相同的对象。然而,在几乎所有web服务器的实现中,都使用了线程,这样 就愿因先后到达的有一个 多多多多多请求,机会由同有一个 多多多线程处理:在前有一个 多多多多多请求处理完成后,线程撤出 该线程,并将该线程重新分配给了上端的请求。而在同一线程中,使用的request对象很机会是同有一个 多多多多多(地址相同,属性不同)。而且即便是对于线程安全的依据,不同的请求使用的request对象地址也机会相同。

与依据2相比,处理了在不同的Controller中重复注入request;而且考虑到java只允许继承有一个 多多多多多基类,不多不多不多不多机会Controller可不能能 继承有些类时,该依据便不再好用。

下面通过具体的代码对类事实现进行说明。

机会多个controller依据中都可不能能 request对象,这样在每个依据中都可不能能 加进一遍request参数

注入不局限于Controller中:在依据1中,这样在Controller中加入request参数。而对于依据2,不仅还可不能能在Controller中注入,还还可不能能在任何Bean中注入,包括Service、Repository及普通的Bean。

分析:在Spring中,Controller的scope是singleton(单例),也而是说在整个web系统中,只有一个 多多多多多多TestController;而且其中注入的request却是线程安全的,愿因在于:

类事依据的主要缺点是request对象写起来冗余不多,主要体现在两点:

该依据实现的原理是,在Controller依据结速英文英文处理请求时,Spring会将request对象赋值到依据参数中。除了request对象,还可不能能通过类事依据获取的参数还有不多不多不多不多,具体还可不能能参见:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-methods

通过这段代码还可不能能看出,生成的RequestAttributes对象是线程局部变量(ThreadLocal),而且request对象也是线程局部变量;这就保证了request对象的线程安全性。

最后,获取request对象的依据与Spring及MVC的版本可不能能 关系;本文基于Spring4进行讨论,且所做的实验可不能能 使用4.1.1版本。

生成RequestAttributes对象的核心代码在类RequestContextHolder中,其中相关代码如下(省略了该类中的无关代码):

既然request对象的线程安全难题可不能能 不得劲关注,为了便于上端的讨论,下面先说明怎样才能测试request对象有无线程安全的。

优缺点

image

下面类事依据及其变种(变种:将request和bindRequest装到子类中)在网上总爱见到:

该依据的主要优点:

https://my.oschina.net/sluggarddd/blog/6781003?fromerr=XhvpvVTi

实际上,在整个请求处理的过程中,request对象是贯穿始终的;也而是说,除了定时器等特殊清况 ,request对象相当于 线程内部内部结构的有一个 多多多多多全局变量。而该依据,相当于 将类事全局变量,传来传去。

补充:上述代码原使用HashSet来判断value有无重复,经日本网友 批评指正,使用线程不安全的集合类验证线程安全性是欠妥的,现已改为ConcurrentSkipListSet。

机会request对象线程安全,服务器中打印结果如下所示:

也而是说,当大伙调用request的依据method时,实际上是调用了由objectFactory.getObject()生成的对象的method依据;objectFactory.getObject()生成的对象才是真正的request对象。

测试结果:线程安全

代码示例

测试的基本思路,是模拟客户端几瓶并发请求,而且在服务器判断哪些地方地方请求有无使用了相同的request对象。

而且,该依据也会地处代码冗余。考虑这样 的场景:web系统中有 不多不多不多不多controller,每个controller中还会使用request对象(类事场景实际上非常频繁),这时就可不能能 写不多不多不多不多次注入request的代码;机会还可不能能 注入response,代码就更繁琐了。下面说明自动注入依据的改进依据,并分析其线程安全性及优缺点。

Controller中获取request对象后,机会要在有些依据中(如service依据、工具类依据等)使用request对象,可不能能 在调用哪些地方地方依据时将request对象作为参数传入。

代码示例

线程安全性

image

其中,要获得request对象可不能能 先调用currentRequestAttributes()依据获得RequestAttributes对象,该依据的实现如下:

继续观察上图,发现objectFactory的类型为WebApplicationContextUtils的内部内部结构类RequestObjectFactory;而RequestObjectFactory代码如下:

优缺点

服务器中Controller代码如下(暂时省略了获取request对象的代码):

此外,本文讨论是围绕代表请求的request对象展开的,但所用依据同样适用于response对象、InputStream/Reader、OutputStream/ Writer等;其中InputStream/Reader还可不能能读取请求中的数据,OutputStream/ Writer还可不能能向响应写入数据。

使用类事依据,当Bean(本例的TestController)初始化时,Spring并这样注入有一个 多多多多多request对象,而是注入了有一个 多多多多多代理(proxy);当Bean中可不能能 使用request对象时,通过该代理获取request对象。

在图中还可不能能看出,request实际上是有一个 多多多多多代理:代理的实现参见AutowireUtils的内部内部结构类ObjectFactoryDelegatingInvocationHandler:

在Spring的Bean中使用request对象:既包括Controller、Service、Repository等MVC的Bean,也包括了Component等普通的Spring Bean。为了方便说明,后文中Spring中的Bean一律简称为Bean。

Controller代码如下;这里列举了BaseController的有一个 多多多多多派生类,机会此时测试代码会有所不同,而且服务端测试代码这样省略;客户端而是需要 进行相应的修改(同时向有一个 多多多多多url发送几瓶并发请求)。

分析:此时request对象是依据参数,相当于 局部变量,毫无难题是线程安全的。

测试结果:线程不安全

机会地处线程安全难题,服务器中打印结果机会如下所示:

http://www.phpchina.com/portal.php?mod=view&aid=40966

优缺点

测试结果:线程安全

https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-methods

代码示例

分析:在理解了依据2的线程安全性的基础上,很容易理解依据3是线程安全的:当创建不同的派生类对象时,基类中的域(这里是注入的request)在不同的派生类对象中会地处不同的内存空间,也而是说将注入request的代码装到基类中对线程安全性这样任何影响;测试结果也证明了类事点。

测试结果:线程安全

文章摘自:http://www.cnblogs.com/kismetv/p/87572100.html

分析:该依据与依据2(自动注入)类事,只不过依据2中通过自动注入实现,本依据通过手动依据调用实现。而且本依据也是线程安全的。

线程安全性

如无特殊说明,本文上端的代码中将省略掉测试代码。

这里有一个 多多多多多多难题可不能能 注意:前面所说的“在处理请求时”使用request对象,究竟是在哪里使用呢?考虑到获取request对象的依据有微小的不同,大体还可不能能分为两类:

https://stackoverflow.com/questions/81004258/spring-3-mvc-accessing-httprequest-from-controller

https://stackoverflow.com/questions/3320674/spring-how-do-i-inject-an-httpservletrequest-into-a-request-scoped-bean

分析:@ModelAttribute注解用在Controller中修饰依据时,其作用是Controller中的每个@RequestMapping依据执行前,该依据还会执行。而且在本例中,bindRequest()的作用是在test()执行前为request对象赋值。觉得bindRequest()中的参数request有一种是线程安全的,但机会TestController是单例的,request作为TestController的有一个 多多多多多域,无法保证线程安全。

为了处理类事难题,有一种依据是在请求处理过程中使线程休眠几秒,这样 还可不能能让每个线程工作的时间足够长,从而处理同有一个 多多多线程分配给不同的请求;另有一种依据,是使用request的有些属性(如参数、header、body等)作为request有无线程安全的依据,机会即便不同的请求先后使用了同有一个 多多多线程(request对象地址也相同),假若使用不同的属性分别构造了两次request对象,这样request对象的使用而是线程安全的。本文使用第二种依据进行测试。

客户端测试代码如下(创建100个线程分别发送请求):

无论是依据2和依据3,都这样在Bean中注入request;机会有些依据(如工具类中static依据)可不能能 使用request对象,则可不能能 在调用哪些地方地方依据时将request参数传递进去。下面介绍的依据4,则还可不能能直接在诸如工具类中的static依据中使用request对象(当然在各种Bean中也还可不能能使用)。

优缺点

此外,本文在讨论获取request对象的依据时,重点讨论该依据的线程安全性、代码的繁琐程度等;在实际的开发过程中,还可不能能 考虑所在项目的规范、代码维护等难题(此处感谢日本网友 的批评指正)。

与依据2相比,将注入次责代码装到到了基类中。

线程安全性

综上所述,Controller中加参数(依据1)、自动注入(依据2和依据3)、手动调用(依据4)可不能能 线程安全的,都还可不能能用来获取request对象。机会系统中request对象使用较少,则使用哪种依据均可;机会使用较多,建议使用自动注入(依据2 和依据3)来减少代码冗余。机会可不能能 在非Bean中使用request对象,既还可不能能在上层调用时通过参数传入,也还可不能能直接在依据中通过手动调用(依据4)获得。

在上述代码中加入断点,查看request对象的属性,如下图所示:

在非Bean中使用request对象:如普通的Java对象的依据中使用,或在类的静态依据中使用。

代码示例

request对象的获取这样从controller结速英文英文,机会使用request对象的地方在函数调用层级比较深的地方,这样整个调用链上的所有依据都可不能能 加进request参数

在使用Spring MVC开发Web系统时,总爱可不能能 在处理请求时使用request对象,比如获取客户端ip地址、请求的url、header中的属性(如cookie、授权信息)、body中的数据等。机会在Spring MVC中,处理请求的Controller、Service等对象可不能能 单例的,而且获取request对象时最可不能能 注意的难题,便是request对象有无线程安全的:当有几瓶并发请求时,还可不能能保证不同请求/线程中使用不同的request对象。

优点:还可不能能在非Bean中直接获取。缺点:机会使用的地方较多,代码非常繁琐;而且还可不能能与有些依据配合使用。

线程安全性