将HttpServletRequest注入控制器
问题内容:
据我所知,默认情况下是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
(RequestObjectFactory
for
HttpServletRequest
)(YMMV)的代理,该代理知道如何检索实际实例。当您使用此代理的任何方法时,它们将委托给该实例。
而且,这是懒惰完成的,因此它不会在初始化时失败。但是,如果在没有可用请求(或尚未注册RequestScope
)的情况下尝试使用Bean,它将失败。
以下是对评论的回应,并进行了一般性的说明。
关于或XML等效proxy- mode
属性@Scope
,默认 为
ScopedProxyMode.NO
。但是,正如javadoc所述
当与非单作用域实例一起使用时, 此代理模式 通常不是有用的,
如果将其用作依赖项,则应优先使用INTERFACES或TARGET_CLASS代理模式。
对于请求范围的Bean,此proxy-mode
值 将不起作用 。您需要根据所需的配置使用INTERFACES
OR
TARGET_CLASS
。
随着scope
设置为request
(使用常量WebApplicationContext.SCOPE_REQUEST
),Spring将使用RequestScope
它
依赖于螺纹结合的
RequestAttributes
实例,这可以通过出口RequestContextListener
,RequestContextFilter
或
DispatcherServlet
。
让我们举一个简单的例子
@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依赖关系链中的某个位置必须有一个代理。