假设我们定义了一个仅具有
@Controller
注释的控制器类。
在类内部,我们定义了
private @Autowired HttpServletRequest request;
变量。
Spring 控制器是单例的。当我们在网络应用程序中将
HttpServletRequest
定义为 @Autowired
时,这会是一个问题吗?
我从一个网站上读到,尽管它是
@Autowired
,但它只是注入了线程变量的代理。
这是真的吗?在多线程环境中,我们可以使用
@Autowired
或将 HttpServletRequest
作为参数传递给控制器类中的每个方法是正确的方法吗?
一些网站说这是一个问题并建议作为参数传递,而很少有人说这是一个问题。
我不明白哪一个是正确的。
两个都好。
@Autowired HttpServletRequest
和作为参数传递是同一件事。
在将
HttpServletRequest
传递给响应 @RequestMapping
函数的调用方法之前,Spring 将 HttpServletRequest
存储到 ThreadLocal
类型变量中。
那个
ThreadLocal
变量是一个线程安全映射,它将 HttpServletRequest
保留在当前线程上下文中。 @Autowired HttpServletRequest
代理 bean 从该 ThreadLocal
变量获取正确的请求。
在这里回答一个古老且已接受的问题。
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 请求。现在看来有点道理了。
另请参阅
首先,为什么必须自动装配?这样做有什么好处?