Spring代理请求属性吗?

时间:2014-01-26 23:29:04

标签: java spring session spring-mvc servlets

如果某个地方我有一个带有@Component HttpSession或HttpServletRequest的单例@Autowired bean“Foo”,那么Foo 本身必须被声明为会话(或请求)作用域,或者我可以将它保存为一个简单的单例 - 在这种情况下,HttpSession和/或HttpServletRequest可能已经作为范围代理注入了Spring?

2 个答案:

答案 0 :(得分:7)

这是一个非常简单的检查行为的测试(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;
}

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

如果你发送了一个请求,你会注意到返回的属性总是null,而且类是

class com.sun.proxy.$Proxy19

因此,即使HttpServletRequest bean是单一作用域,您也总是得到一个不同的@Component对象。


以下是解释:

当您实例化WebApplicationContent时,它会注册一些特殊的ObjectFactory实例,以解析基础BeanFactory中的某些 web 类型。这是在WebApplicationContextUtils.registerWebApplicationScopes(..)中完成的。其中一个是以下

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

当Spring扫描你的bean并确定它需要自动装配HttpServletRequest(这是ServletRequest的子类型)字段时,它将在其可解析的依赖关系的地图中查找并获取此{{ 1}}。

因为这是一个RequestObjectFactory并且注入目标是接口类型,所以Spring将创建一个代理到每个请求上由ObjectFactory创建/返回的对象的代理。这是在RequestObjectFactory

中完成的

因此,您的AutowireUtils.resolveAutowiringValue(..) bean不需要作为请求范围。

答案 1 :(得分:1)

我的理解是Spring确实使用了代理,是的。 Spring允许您通过将代理注入单例来将请求或会话范围的对象注入到单例范围对象中。

对于Spring MVC,我相信注入的代理由ThreadLocal变量支持,因为每个请求都绑定了一个线程。然后,真实的HttpServletRequest可通过此注入的代理获得,该代理在调用时委托给ThreadLocal

因此,您不需要将“Foo”声明为会话或请求作用域,并且可以将其保留为Singleton。