将HttpServletRequest注入Controller

时间:2014-03-26 22:06:54

标签: java spring spring-mvc

据我所知,默认情况下是Spring MVC单例中的控制器。 HttpServletRequest传递给控制器​​处理程序方法。好吧,虽然HttpServletRequest是请求范围的,但我经常看到HttpServletRequest获取@Autowired到控制器字段中,如下所示:

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

这可能是个问题吗?更一般的问题:如果将一个请求范围的组件注入一个单独的组件会发生什么?

2 个答案:

答案 0 :(得分:13)

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

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


以下是对评论的回应并总体上澄清。

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

  

与非单身人士一起使用时,此代理模式通常不常用   范围实例,它应该支持使用INTERFACES或   TARGET_CLASS代理模式,如果它将被用作依赖项。

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

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

  

依赖于线程绑定的RequestAttributes实例,可以是   通过RequestContextListenerRequestContextFilter或。{   DispatcherServlet

让我们来看看这个简单的例子

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

Spring将生成两个 bean定义:一个用于注入的bean,一个是singleton,另一个用于在每个请求上生成的请求范围bean。

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

bean.method();

被召唤。

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

documentation

  

Spring IoC容器不仅管理你的实例化   对象(bean),也是协作者的联络(或   依赖)。 如果要注入(例如)HTTP请求   scoped bean到另一个bean,你必须注入一个AOP代理   作用域的bean。也就是说,你需要注入一个代理对象   公开与作用域对象相同的公共接口但可以   还从相关范围中检索真实的目标对象(for   例如,一个HTTP请求)和委托方法调用真实的   对象

如果正确实施,所有急切加载的请求范围bean都将是代理。同样,没有急切加载的请求范围bean将自己代理或通过代理加载。如果没有绑定到当前线程的HttpSerlvetRequest,则会失败。基本上,在请求范围bean的bean依赖关系链中的某处需要代理。

答案 1 :(得分:0)

  

如果将一个reqeust-scoped组件注入单例,会发生什么?

尝试一下,在应用程序上下文初始化期间,您将获得BeanCreationException¹。错误消息清楚地解释了为什么HttpServletRequest

不会发生这种情况
  

范围'请求'对当前线程无效;考虑为这个bean定义一个范围代理,如果你打算从一个单例引用它;

显然HttpServletRequest是一个范围代理。如果你想在单例中使用较小范围的bean,它们必须是代理。该文档详细阐述了Scoped beans as dependencies中较小的范围依赖关系。

[1]:除非您没有更改proxyMode的{​​{3}},NO或尝试将@Lazy注入{{1}}。后者可能会导致有效的应用程序上下文,但可能会导致请求范围的bean像单例一样运行(例如,如果将请求范围的bean注入单例中)。