@Autowired HttpServletRequest 与作为参数传递 - 最佳实践

问题描述 投票:0回答:3

假设我们定义了一个仅具有

@Controller
注释的控制器类。

在类内部,我们定义了

private @Autowired HttpServletRequest request;
变量。

Spring 控制器是单例的。当我们在网络应用程序中将

HttpServletRequest
定义为
@Autowired
时,这会是一个问题吗?

我从一个网站上读到,尽管它是

@Autowired
,但它只是注入了线程变量的代理。

这是真的吗?在多线程环境中,我们可以使用

@Autowired
或将
HttpServletRequest
作为参数传递给控制器类中的每个方法是正确的方法吗?

一些网站说这是一个问题并建议作为参数传递,而很少有人说这是一个问题。

我不明白哪一个是正确的。

spring spring-mvc
3个回答
49
投票

两个都好。

@Autowired HttpServletRequest
和作为参数传递是同一件事。

在将

HttpServletRequest
传递给响应
@RequestMapping
函数的调用方法之前,Spring 将
HttpServletRequest
存储到
ThreadLocal
类型变量中。

那个

ThreadLocal
变量是一个线程安全映射,它将
HttpServletRequest
保留在当前线程上下文中。
@Autowired HttpServletRequest
代理 bean 从该
ThreadLocal
变量获取正确的请求。


1
投票

在这里回答一个古老且已接受的问题。

比较

HttpServletRequest
是受支持的控制器方法参数之一,如Spring Web MVC文档中指定的

@Autowired
方式,从我的搜索结果中我在官方网站上找不到太多。但许多 SO 答案提到“Spring 将 HttpServletRequest 存储到 ThreadLocal 变量中......它将根据检查源代码注入每个线程”。

我做了一些检查

假设有道理,但切入点在哪里?我尝试打印自动装配的

HttpServletRequest
bean 的运行时类名称:

// ... imports ...

@RestController
@Slf4j
public class K {
  @Autowired private HttpServletRequest request;

  @GetMapping public ResponseEntity<String> getIt() {
    log.info("GET request rt class is {}", request.getClass().getName());
    return ResponseEntity.ok("k");
  }
}

输出类似于

jdk.proxy2.$Proxy77
,对,它是注入的代理。那么应该使用
Proxy.getInvocationHandler(request).getClass().getName()
。现在输出是
org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler
,它是 AutowireUtils 中的私有嵌套类,它有一个类型为
ObjectFactory
的字段。
ObjectFactory
有 16 种实现(您可以使用 IDE 来查看),最有可能给出 ServletRequest 的实现(
根据假设
)是
RequestObjectFactory
 中的私有嵌套类 
WebApplicationContextUtils

//...
private static ServletRequestAttributes currentRequestAttributes() {
    RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
    if (!(requestAttr instanceof ServletRequestAttributes)) {
        throw new IllegalStateException("Current request is not a servlet request");
    }
    return (ServletRequestAttributes) requestAttr;
}

/**
 * Factory that exposes the current request object on demand.
 */
@SuppressWarnings("serial")
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    @Override
    public ServletRequest getObject() {
        return currentRequestAttributes().getRequest();
    }
    // ...
}
// ...

如您所见,它涉及到

RequestContextHolder
,一个 Holder 类,以线程绑定
RequestAttributes
对象
的形式公开 Web 请求。现在看来有点道理了。


另请参阅


0
投票

首先,为什么必须自动装配?这样做有什么好处?

© www.soinside.com 2019 - 2024. All rights reserved.