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