繁体   English   中英

将HttpServletRequest注入控制器

[英]Inject HttpServletRequest into Controller

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

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

这可能是个问题吗? 还有一个更笼统的问题:如果将要求范围内的组件注入单例,会发生什么?

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

而且,这是懒惰完成的,因此它不会在初始化时失败。 但是,如果在没有可用请求时尝试使用Bean(或者未注册RequestScope ),它将失败。


以下是对评论的回应,并进行了一般性的说明。

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

当与非单作用域实例一起使用时,此代理模式通常不是有用的,如果将其用作依赖项,则应优先使用INTERFACES或TARGET_CLASS代理模式。

对于请求范围的Bean,此proxy-mode将不起作用 您需要根据所需的配置使用INTERFACESTARGET_CLASS

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

依赖于线程绑定的RequestAttributes实例,该实例可以通过RequestContextListenerRequestContextFilterDispatcherServlet导出。

让我们举一个简单的例子

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

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

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

bean.method();

叫做。

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

文档说明

Spring IoC容器不仅管理对象(bean)的实例化,而且还管理协作者(或依赖项)的连接。 如果要将(例如)HTTP请求范围的bean注入另一个bean,则必须注入AOP代理来代替范围的bean。 也就是说,您需要注入一个代理对象,该代理对象公开与范围对象相同的公共接口,但还可以从相关范围(例如,HTTP请求)中检索实际的目标对象,并将委托方法调用到实际对象上。

如果正确实现,所有热切加载的请求范围的Bean将成为代理。 同样,不急于加载的请求范围的Bean要么是代理本身,要么是通过代理加载的。 如果没有HttpSerlvetRequest绑定到当前线程,则此操作将失败。 基本上,对于请求范围内的bean,在bean依赖关系链中的某个位置必须有一个代理。

如果将需求范围内的组件注入单例中会发生什么?

尝试一下,您将在应用程序上下文初始化期间得到BeanCreationException 错误消息清楚地说明了为什么HttpServletRequest不会发生这种情况:

范围“请求”对于当前线程无效。 如果您打算从单例中引用它,请考虑为此bean定义作用域代理

因此,显然HttpServletRequest是作用域代理。 如果要在单例中使用较小范围的bean,则它们必须是代理。 该文档详细介绍了Scoped bean中较小的范围依赖项作为依赖项

[1]:除非你没有更改默认行为proxyMode ,这是NO或尝试用注入它@Lazy 后者可能会导致进入有效的应用程序上下文,但可能导致请求范围内的bean像单例一样工作(例如,如果请求范围内的bean被注入到单例中)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM