简体   繁体   English

将HttpServletRequest注入控制器

[英]Inject HttpServletRequest into Controller

As I know per default are controllers in Spring MVC singletons. 据我所知,默认情况下是Spring MVC单例中的控制器。 HttpServletRequest passed offen to the controller handler method. HttpServletRequest将offen传递给控制器​​处理程序方法。 And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets @Autowired into the controller field, like this: 没关系,虽然HttpServletRequest是请求范围的,但是我经常看到HttpServletRequest@Autowired进入控制器字段,如下所示:

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

Could be this a problem? 这可能是个问题吗? And more general question: What happens if inject a reqeust-scoped component into a singleton? 还有一个更笼统的问题:如果将要求范围内的组件注入单例,会发生什么?

No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. 不,对于HttpServletRequest来说这不是问题,对于其他请求范围的Bean也不应如此。 Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory ( RequestObjectFactory for HttpServletRequest ) (YMMV) that knows how to retrieve the actual instance. 基本上,Spring将生成一个代理HttpServletRequest ,该代理包装了某种ObjectFactory (用于HttpServletRequest RequestObjectFactory )(YMMV),该对象知道如何检索实际实例。 When you use any of the methods of this proxy, they will delegate to that instance. 当您使用此代理的任何方法时,它们将委托给该实例。

What's more, this is done lazily, so it won't fail at initialization. 而且,这是懒惰完成的,因此它不会在初始化时失败。 It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope ). 但是,如果在没有可用请求时尝试使用Bean(或者未注册RequestScope ),它将失败。


The following is in response to the comments and to clarify in general. 以下是对评论的回应,并进行了一般性的说明。

Regarding the proxy-mode attribute of @Scope or the XML equivalent, the default is ScopedProxyMode.NO . 关于@Scope或XML等效项的proxy-mode属性,默认值为 ScopedProxyMode.NO However, as the javadoc states 但是,正如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. 当与非单作用域实例一起使用时,此代理模式通常不是有用的,如果将其用作依赖项,则应优先使用INTERFACES或TARGET_CLASS代理模式。

With request scoped beans, this proxy-mode value will not work . 对于请求范围的Bean,此proxy-mode将不起作用 You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want. 您需要根据所需的配置使用INTERFACESTARGET_CLASS

With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST ), Spring will use RequestScope which scope设置为request (使用常量WebApplicationContext.SCOPE_REQUEST ),Spring将使用RequestScope

Relies on a thread-bound RequestAttributes instance, which can be exported through RequestContextListener , RequestContextFilter or DispatcherServlet . 依赖于线程绑定的RequestAttributes实例,该实例可以通过RequestContextListenerRequestContextFilterDispatcherServlet导出。

Let's take this simple example 让我们举一个简单的例子

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

Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request. Spring将生成两个 bean定义:一个用于注入的bean,一个单例,一个用于在每个请求中生成的请求范围的bean。

From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. 通过这些bean定义,Spring会将单例初始化为具有目标类类型的代理。 In this example, that is RequestScopedBean . 在此示例中,这就是RequestScopedBean The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. 代理将包含它需要产生或在需要时返回实际bean所需的状态,即。 when a method is called on the proxy. 在代理上调用方法时。 For example, when 例如,当

bean.method();

is called. 叫做。

This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. 此状态基本上是对基础BeanFactory的引用以及请求范围的Bean定义的名称。 It will use these two to generate a new bean and then call method() on that instance. 它将使用这两个生成一个新bean,然后在该实例上调用method()

The documentation states 文档说明

The Spring IoC container manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). Spring IoC容器不仅管理对象(bean)的实例化,而且还管理协作者(或依赖项)的连接。 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. 如果要将(例如)HTTP请求范围的bean注入另一个bean,则必须注入AOP代理来代替范围的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. 也就是说,您需要注入一个代理对象,该代理对象公开与范围对象相同的公共接口,但还可以从相关范围(例如,HTTP请求)中检索实际的目标对象,并将委托方法调用到实际对象上。

All eagerly loaded request scoped beans, if implemented correctly, will be proxies. 如果正确实现,所有热切加载的请求范围的Bean将成为代理。 Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. 同样,不急于加载的请求范围的Bean要么是代理本身,要么是通过代理加载的。 This will fail if there is no HttpSerlvetRequest bound to the current thread. 如果没有HttpSerlvetRequest绑定到当前线程,则此操作将失败。 Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans. 基本上,对于请求范围内的bean,在bean依赖关系链中的某个位置必须有一个代理。

What happens if inject a reqeust-scoped component into a singleton? 如果将需求范围内的组件注入单例中会发生什么?

Try it and you'll get a BeanCreationException ¹ during application context initialization. 尝试一下,您将在应用程序上下文初始化期间得到BeanCreationException The error message clearly explains why this doesn't happen with HttpServletRequest : 错误消息清楚地说明了为什么HttpServletRequest不会发生这种情况:

Scope 'request' is not active for the current thread; 范围“请求”对于当前线程无效。 consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; 如果您打算从单例中引用它,请考虑为此bean定义作用域代理

So obviously HttpServletRequest is a scoped proxy. 因此,显然HttpServletRequest是作用域代理。 If you want to use beans of smaller scopes in singletons they have to be proxies. 如果要在单例中使用较小范围的bean,则它们必须是代理。 The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies . 该文档详细介绍了Scoped bean中较小的范围依赖项作为依赖项

[1]: unless you didn't change the default behaviour for proxyMode , which is NO or try to inject it with @Lazy . [1]:除非你没有更改默认行为proxyMode ,这是NO或尝试用注入它@Lazy The latter might result into a valid application context but might lead to request scoped beans acting like singletons (eg if a request scoped bean is injected into a singleton). 后者可能会导致进入有效的应用程序上下文,但可能导致请求范围内的bean像单例一样工作(例如,如果请求范围内的bean被注入到单例中)。

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

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