java - 将 HttpServletRequest 注入(inject) Controller

标签 java spring spring-mvc

据我所知,默认情况下是 Spring MVC 单例中的 Controller 。 HttpServletRequest 传递给 Controller ​​处理程序方法。没关系,虽然 HttpServletRequest 是请求范围的,但我经常看到 HttpServletRequest@Autowired 放入 Controller 字段,如下所示:

@Controller("CMSProductComponentController")
@RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
    @Autowired
    private HttpServletRequest request;
}

这可能是个问题吗?还有一个更普遍的问题:如果将一个请求范围的组件注入(inject)到单例中会发生什么?

最佳答案

不,对于 HttpServletRequest 不会有问题,对于其他请求范围的 bean 也不应该。基本上,Spring 将生成一个代理 HttpServletRequest 包装某种 ObjectFactory(RequestObjectFactory for HttpServletRequest)(YMMV)知道如何检索实际实例。当您使用此代理的任何方法时,它们将委托(delegate)给该实例。

更重要的是,这是延迟完成的,所以它不会在初始化时失败。但是,如果您在没有可用请求的情况下尝试使用 bean(或者如果您尚未注册 RequestScope),它将失败。


以下是对评论的回应和一般性的澄清。

关于@Scopeproxy-mode属性或等效的 XML,默认 ScopedProxyMode.NO .但是,正如 javadoc 所述

This proxy-mode is not typically useful when used with a non-singleton scoped instance, which should favor the use of the INTERFACES or TARGET_CLASS proxy-modes instead if it is to be used as a dependency.

对于请求范围的 bean,此 proxy-mode将不起作用。您需要使用 INTERFACESTARGET_CLASS,具体取决于您想要的配置。

scope 设置为 request(使用常量 WebApplicationContext.SCOPE_REQUEST ),Spring 将使用 RequestScope其中

Relies on a thread-bound RequestAttributes instance, which can be exported through RequestContextListener, RequestContextFilter or DispatcherServlet.

让我们举这个简单的例子

@Component
@Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
    public void method() {}
}
...
@Autowired
private RequestScopedBean bean;

Spring 将生成 两个 bean 定义:一个用于注入(inject)的 bean,一个单例,一个用于在每个请求上生成的请求范围 bean。

根据这些 bean 定义,Spring 将使用目标类的类型将单例初始化为代理。在此示例中,即 RequestScopedBean。代理将包含它需要的状态来生成或在需要时返回实际的 bean,即。在代理上调用方法时。例如,当

bean.method();

被调用。

此状态基本上是对底层 BeanFactory 和请求范围 bean 定义的名称的引用。它将使用这两个生成一个新的 bean,然后在该实例上调用 method()

documentation状态

The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). If you want to inject (for example) an HTTP request scoped bean into another bean, you must inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object but that can also retrieve the real, target object from the relevant scope (for example, an HTTP request) and delegate method calls onto the real object.

如果正确实现,所有急切加载的请求范围 bean 都将成为代理。类似地,未急切加载的请求范围 bean 要么是代理本身,要么是通过代理加载。如果没有 HttpSerlvetRequest 绑定(bind)到当前线程,这将失败。基本上,对于请求范围的 bean,在 bean 依赖链的某个地方需要一个代理。

关于java - 将 HttpServletRequest 注入(inject) Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22674044/

相关文章:

java - 如何在鼠标指针处读取 SWT Canvas 上像素的颜色?

java - 特定时区的日历不显示 android 和 java 中的夏令时

java - 在没有 Spring Boot 应用程序的情况下使用 Spring Boot Actuator

尝试呈现 index.html 时,Spring Boot + Thymeleaf = "Whitelabel Error Page"

java - Spring ClassPathXmlApplicationContext 空指针异常

java - 加速递归函数

java - 为什么我的Spark程序在IntelliJ中运行良好,但提交后抛出 "org.apache.spark.SparkException: Task not serializable"?

java - 仅加载一次 url

java - spring 是否有办法在应用程序首次加载时加载东西?在全局范围内

java - 俄语字符显示为 ???在 Spring-MVC 中