据我所知,默认情况下是Spring MVC单例中的控制器。 HttpServletRequest
传递给控制器处理程序方法。好吧,虽然HttpServletRequest
是请求范围的,但我经常看到HttpServletRequest
获取@Autowired
到控制器字段中,如下所示:
@Controller("CMSProductComponentController")
@RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
@Autowired
private HttpServletRequest request;
}
这可能是个问题吗?更一般的问题:如果将一个请求范围的组件注入一个单独的组件会发生什么?
答案 0 :(得分:13)
不,对于HttpServletRequest
,它不会成为问题,也不应该用于其他请求范围的bean。基本上,Spring将生成一个代理HttpServletRequest
,它包含某种知道如何检索实际实例的ObjectFactory
(RequestObjectFactory
HttpServletRequest
)(YMMV)。当您使用此代理的任何方法时,它们将委派给该实例。
更重要的是,这是懒洋洋地完成的,所以它在初始化时不会失败。但是,如果您在没有可用请求时尝试使用bean(或者您尚未注册RequestScope
),则会失败。
以下是对评论的回应并总体上澄清。
关于@Scope
的proxy-mode
属性或等效的XML,默认是 ScopedProxyMode.NO
。但是,正如javadoc所述
与非单身人士一起使用时,此代理模式通常不常用 范围实例,它应该支持使用INTERFACES或 TARGET_CLASS代理模式,如果它将被用作依赖项。
对于请求范围内的bean,此proxy-mode
值将不起作用。您需要使用INTERFACES
或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,一个是singleton,另一个用于在每个请求上生成的请求范围bean。
从这些bean定义中,Spring会将单例初始化为具有目标类类型的代理。在此示例中,即RequestScopedBean
。代理将包含在需要时生成或返回实际bean所需的状态,即。在代理上调用方法时。例如,
bean.method();
被召唤。
此状态基本上是对基础BeanFactory
的引用以及请求范围的bean定义的名称。它将使用这两个来生成一个新bean,然后在该实例上调用method()
。
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注入单例中)。
子>