HttpSession-s之间共享的Spring会话bean

时间:2013-12-17 17:15:04

标签: java spring spring-mvc session-bean

我正试图在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之间共享,但我期待两个Cart实例。

如果我让bean实现一个接口,使用注释驱动的approch和组件扫描:

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());
    }
}

我错过了什么吗?我是否误解了会话bean的含义?

2 个答案:

答案 0 :(得分:4)

public class HomeController {
  @Autowired 
  private Cart cart; <-- Proxy

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

答案 1 :(得分:3)

正在进行代理和授权的很多

此字段

@Autowired 
private Cart cart;

其中Cart是会话范围的代理,您可以在日志中看到

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

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

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

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

cart.hashCode()

委托SimpleBeanTargetSource对象(如果你问我,那就错误了)。但如果你做了

cart.toString();

你会看到实际到达底层Cart对象的区别。


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