【问题标题】:Spring session bean shared between HttpSession-sHttpSession-s 之间共享的 Spring 会话 bean
【发布时间】:2013-12-18 02:03:19
【问题描述】:

我试图理解 Spring 中的会话 bean。 我正在阅读的书说,关于他们:

bean 在需要时创建并存储在 javax.servlet.http.HttpSession 中。当会话被销毁时,bean 实例也被销毁。

我尝试了以下示例:

豆子:

package com.at.test.web;

public class Cart {
    public static int dummy = 0;
    public Cart() {
        System.out.println("Cart::<init> with hashCode " + hashCode());
    }
}

bean 定义:

<beans:bean id="cartBean" class="com.at.test.web.Cart" scope="session">
    <apo:scoped-proxy/>
</beans:bean>

控制器:

@Controller
public class HomeController {
    @Autowired 
    private Cart cart;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(HttpSession session, Model model) {
      System.out.println("Cart is: " + cart.hashCode() 
          + " ; dummy = " + (cart.dummy++) 
          + " (" + cart.getClass().getCanonicalName() + ")" 
          + "; session is: " + session.hashCode());
      return "home.jsp";
  }
}

这是 Tomcat 启动时发生的情况:

Cart::<init> with hashCode 970109301

我认为 Spring 需要这个实例来创建 CGLIB 代理。无论如何,我不确定。

启动后,我用两个不同的浏览器有两个不同的HttpSession。 调用控制器时的结果是:

Cart is: 578093288 ; dummy = 0 (com.at.test.web.Cart$$EnhancerByCGLIB$$2eb8334f); session is: 1013723725
Cart is: 578093288 ; dummy = 1 (com.at.test.web.Cart$$EnhancerByCGLIB$$2eb8334f); session is: 1060682497

购物车实例似乎在 HttpSession-s 之间共享,但我期待有两个购物车实例。

如果我让 bean 实现一个接口,使用注解驱动的方法和组件扫描也是一样的:

public interface ICart {}

--

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.INTERFACES)
public class Cart implements ICart {
    public static int dummy = 0;
    public Cart() {
        System.out.println("Cart::<init> with hashCode " + hashCode());
    }
}

我错过了什么吗?我是不是误解了 session bean 的意思?

【问题讨论】:

    标签: java spring spring-mvc session-bean


    【解决方案1】:
    public class HomeController {
      @Autowired 
      private Cart cart; <-- Proxy
    

    注入HomeController 实例的Cart 实例只是将方法调用委托给“真实”实例的代理。 Cart 类本身还没有自己的方法或状态,因此您当然不会注意到会话之间的任何差异。

    【讨论】:

      【解决方案2】:

      很多代理和委派正在进行。

      这个字段

      @Autowired 
      private Cart cart;
      

      Cart 的会话范围将被代理,如您在日志中看到的那样

      com.at.test.web.Cart$$EnhancerByCGLIB$$2eb8334f
      

      但是这个代理没有包装Cart 对象。它包装了一个SimpleBeanTargetSource,它负责从BeanFactory 获取一个Cart bean。

      您的 bean 定义附加了一个 SessionScope 对象,该对象负责通过 static ThreadLocal 中的 RequestContextHolder 字段检查您的 HttpSession。当请求从BeanFactory 获取一个bean 时,它会将操作委托给SessionScope 对象,该对象将检查HttpSession,如果存在则使用那里的一个,如果不存在则创建并注册一个新的不。

      您在测试中没有注意到这一点,因为

      cart.hashCode()
      

      委派给SimpleBeanTargetSource 对象(如果你问我,这是不正确的)。但是如果你这样做了

      cart.toString();
      

      您会看到实际到达底层Cart 对象的差异。


      根据您使用的范围和代理策略,这一切可能会有所不同,但最终目标仍然可以实现。

      【讨论】:

        猜你喜欢
        • 2012-03-27
        • 2011-01-29
        • 2018-06-25
        • 1970-01-01
        • 1970-01-01
        • 2014-01-29
        • 2011-12-20
        • 2013-02-15
        • 1970-01-01
        相关资源
        最近更新 更多