据我所知,默认情况下是 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
),它将失败。
以下是对评论的回应和一般性的澄清。
关于@Scope
的proxy-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
值 将不起作用。您需要使用 INTERFACES
或 TARGET_CLASS
,具体取决于您想要的配置。
将 scope
设置为 request
(使用常量 WebApplicationContext.SCOPE_REQUEST
),Spring 将使用 RequestScope
其中
Relies on a thread-bound
RequestAttributes
instance, which can be exported throughRequestContextListener
,RequestContextFilter
orDispatcherServlet
.
让我们举这个简单的例子
@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()
。
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/