当前位置:   article > 正文

Spring获取HttpServletRequst 的几种方法_spring 获取httprequest

spring 获取httprequest

1.controller中加参数

这种方法的实现最简单

  1. @Controller
  2. public class TestController {
  3. @RequestMapping("/test")
  4. public void test(HttpServletRequest request) throws InterruptedException {
  5. // 模拟程序执行了一段时间
  6. Thread.sleep(1000);
  7. }
  8. }

Controller获取到request对象,如果需要在service中也使用这个对象,需要将request对象传递进去;这个方法是线程安全的;但是缺点比较明显:

1>如果在controller中多个方法都需要添加request对象,那么在每个方法的参数中都需要添加一遍;

2>request对象的获取只能从controller开始,如果使用request对象的地方在函数中调用的层次比较深,那么整个调用链上都需要传入该参数,相当不方便;

2.自动注入的方式

  1. @Controller
  2. public class TestController{
  3. @Autowired
  4. private HttpServletRequest request; //自动注入request
  5. @RequestMapping("/test")
  6. public void test() throws InterruptedException{
  7. //模拟程序执行了一段时间
  8. Thread.sleep(1000);
  9. }
  10. }

这种方式同样是线程安全的;实现分析:Spring 中的controller默认是单例模式,但是在其中注入的httpServletReqeust却是安全安全的,是因为初始化的时候,并不是注入了一个request对象,而是注入了一个代理(proxy),当bean中需要该对象的时候,通过代理再去获取;可以断点调试下看看


可以看到request实际是一个代理,代理具体的实现如下所示;之前的文章有提到动态代理的实现,如果调用request方法的时候,其实调用objectFactory对象的方法来执行

  1. private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
  2. private final ObjectFactory<?> objectFactory;
  3. public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
  4. this.objectFactory = objectFactory;
  5. }
  6. @Override
  7. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  8. String methodName = method.getName();
  9. if (methodName.equals("equals")) {
  10. // Only consider equal when proxies are identical.
  11. return (proxy == args[0]);
  12. }
  13. else if (methodName.equals("hashCode")) {
  14. // Use hashCode of proxy.
  15. return System.identityHashCode(proxy);
  16. }
  17. else if (methodName.equals("toString")) {
  18. return this.objectFactory.toString();
  19. }
  20. try {
  21. return method.invoke(this.objectFactory.getObject(), args);
  22. }
  23. catch (InvocationTargetException ex) {
  24. throw ex.getTargetException();
  25. }
  26. }
  27. }

下面跟踪下objectFactory对象,从上面可以看出是WebApplicationContextUtils类的RequestObjectFactory对象,具体代码如下

  1. private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
  2. @Override
  3. public ServletRequest getObject() {
  4. return currentRequestAttributes().getRequest();
  5. }
  6. @Override
  7. public String toString() {
  8. return "Current HttpServletRequest";
  9. }
  10. }
  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. }
  1. public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
  2. RequestAttributes attributes = getRequestAttributes();
  3. if (attributes == null) {
  1. public static RequestAttributes getRequestAttributes() {
  2. RequestAttributes attributes = requestAttributesHolder.get();
  3. if (attributes == null) {
  4. attributes = inheritableRequestAttributesHolder.get();
  5. }
  6. return attributes;
  7. }
  1. private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
  2. new NamedThreadLocal<RequestAttributes>("Request attributes");
  3. private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
  4. new NamedInheritableThreadLocal<RequestAttributes>("Request context");

相关的代码片段如图,这里可以看出生成request对象是线程的局部变量ThreadLocal,因此这里的request也是局部变量;所有是线程安全的;

这种方法的优点:1>.注入不局限于controller中,可以是任何的bean,service,Repository及普通的Bean;

2>.除了注入request对象,该方法还可以注入其他scope为request或session的对象,如response对象、session对象等;并保证线程安全。

3>.大量减少代码的冗余,不用通过层层的参数传递的方式传递很深;

4>.注意一点,如果在另外的线程,比如new了一个线程或者在@Asyn标记的方法中,会创建一个新的线程,那么这种方式不行的;

3.手动注入

  1. @Controller
  2. public class TestController {
  3. @RequestMapping("/test")
  4. public void test() throws InterruptedException {
  5. HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
  6. // 模拟程序执行了一段时间
  7. Thread.sleep(1000);
  8. }
  9. }
线程安全,可以在非bean中直接获取;







声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/310095
推荐阅读
相关标签
  

闽ICP备14008679号