As I know per default are controllers in Spring MVC singletons. HttpServletRequest
passed offen to the controller handler method. And its ok, while HttpServletRequest
is request-scoped, but I see often HttpServletRequest
gets @Autowired
into the controller field, like this:
@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. 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. 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
).
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
. However, as the javadoc states
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.
With request scoped beans, this proxy-mode
value will not work. You'll need to use INTERFACES
OR TARGET_CLASS
depending on the configuration you want.
With scope
set to request
(use the constant WebApplicationContext.SCOPE_REQUEST
), Spring will use RequestScope
which
Relies on a thread-bound
RequestAttributes
instance, which can be exported throughRequestContextListener
,RequestContextFilter
orDispatcherServlet
.
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.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean
. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. 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. It will use these two to generate a new bean and then call method()
on that instance.
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). 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.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest
bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With