【问题标题】:Does Spring proxy request attributes?Spring代理请求属性吗?
【发布时间】:2014-02-17 16:34:26
【问题描述】:

如果我有一个带有@Autowired HttpSession 或 HttpServletRequest 的单例 @Component bean "Foo",Foo 本身 是否必须声明为会话(或请求)范围,或者我可以只声明将其保留为简单的单例 --- 在这种情况下,HttpSession 和/或 HttpServletRequest 可能已经通过 Spring 作为范围代理注入?

【问题讨论】:

    标签: java spring session spring-mvc servlets


    【解决方案1】:

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

    因此,即使 @Component bean 是单例范围的,您总是会得到不同的 HttpServletRequest 对象。


    解释如下:

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

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

    当 Spring 扫描您的 bean 并确定它需要自动装配 HttpServletRequest(它是 ServletRequest 的子类型)字段时,它将查看其可解析依赖关系的映射并获取此 RequestObjectFactory。

    因为这是一个ObjectFactory 并且注入目标是一个接口类型,所以Spring 将创建一个该类型的代理,该代理委托给RequestObjectFactory 在每个请求上创建/返回的对象。这是在AutowireUtils.resolveAutowiringValue(..) 中完成的。

    因此,您的 Foo bean 不需要在请求范围内。

    【讨论】:

      【解决方案2】:

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

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

      因此,您无需将“Foo”声明为会话或请求范围,并且可以将其保留为 Singleton。

      【讨论】:

        猜你喜欢
        • 2012-09-13
        • 2019-08-05
        • 2018-02-15
        • 2018-08-11
        • 2018-09-17
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多