简体   繁体   中英

Inject HttpServletRequest into Controller

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 through RequestContextListener , RequestContextFilter or DispatcherServlet .

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.

What happens if inject a reqeust-scoped component into a singleton?

Try it and you'll get a BeanCreationException ¹ during application context initialization. The error message clearly explains why this doesn't happen with 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;

So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies .

[1]: unless you didn't change the default behaviour for proxyMode , which is NO or try to inject it with @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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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