ManRow
ManRow

Reputation: 1593

Does Spring proxy request attributes?

If somewhere I have a singleton @Component bean "Foo" with a @Autowired HttpSession or HttpServletRequest, does Foo itself have to be declared session (or request) scoped, or can I just keep it as a simple singleton --- in which case HttpSession and/or HttpServletRequest are probably already injected as scoped proxies anyway via Spring?

Upvotes: 3

Views: 1545

Answers (2)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280174

Here's a pretty simple test to check behavior (Spring 4.0.0.RELEASE)

@Controller
@RequestMapping("/service")
public class NewController {
    @RequestMapping(method = RequestMethod.GET)
    public @ResponseBody String test(ModelMap model) {
        System.out.println(requestEntity.request.getAttribute("type")); // get it
        requestEntity.request.setAttribute("type", "Scope"); // set it so that we can make sure that our second request doesn't contain it
        System.out.println(requestEntity.request.getClass());
        return "whatever";
    }

    @Autowired
    private Foo requestEntity;
}

and

@Component
public class Foo {
    @Autowired
    public HttpServletRequest request;
}

If you send a request, you'll note that the attribute returned is always null and that the class is something like

class com.sun.proxy.$Proxy19

Therefore you are always getting a different HttpServletRequest object even though the @Component bean is singleton scoped.


Here's the explanation:

When you instantiate a WebApplicationContent, it registers some special ObjectFactory instances for resolving some web types in the underlying BeanFactory. This is done in WebApplicationContextUtils.registerWebApplicationScopes(..). One of these is the following

beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());

When Spring scans your beans and determines that it needs to autowire the HttpServletRequest (which is a sub type of ServletRequest) field, it will look in its map of resolvable dependencies and get this RequestObjectFactory.

Because this is an ObjectFactory and the injection target is an interface type, Spring will create a Proxy of that type that delegates to the object created/returned by the RequestObjectFactory on each request. This is done in AutowireUtils.resolveAutowiringValue(..).

As such, your Foo bean does not need to be request scoped.

Upvotes: 8

ATG
ATG

Reputation: 1707

My understanding is that Spring does use a proxy, yes. Spring allows you to inject request or session-scoped objects into singleton-scope objects by injecting a proxy into the singleton.

For Spring MVC, I believe the injected proxy is backed by a ThreadLocal variable because each request is bound do a thread. The real HttpServletRequest is then available via this injected proxy that delegates onto the ThreadLocal when invoked.

Therefore, you don't need to declare "Foo" to be session or request scoped and can keep it as a Singleton.

Upvotes: 1

Related Questions