我正在尝试在春季取消会话豆子。我正在读的书说,关于他们,
: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());
}
}
豆的定义:
<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());
}
}
我错过了什么吗?我是否误解了会话豆的含义?
public class HomeController {
@Autowired
private Cart cart; <-- Proxy
注入到HomeController
实例中的Cart
实例只是将方法调用委托给"真实"实例的代理。Cart
类本身还没有自己的方法或状态,所以你当然不会注意到会话之间的任何区别。
有很多代理和委派正在进行。
此字段
@Autowired
private Cart cart;
会话范围的Cart
将被代理,如您在日志中看到的那样
com.at.test.web.Cart$$EnhancerByCGLIB$$2eb8334f
但是此代理不会包装Cart
对象。它正在包装一个SimpleBeanTargetSource
,负责从BeanFactory
中获取Cart
豆。
您的 Bean 定义附加了一个 SessionScope
对象,该对象负责通过 RequestContextHolder
中的static
ThreadLocal
字段检查您的HttpSession
。当请求从BeanFactory
获取 bean 时,它会将操作委托给 SessionScope
对象,该对象将检查HttpSession
,如果存在,则使用那里的 bean,如果没有,则创建并注册一个新对象。
您在测试中没有注意到这一点,因为
cart.hashCode()
委托给SimpleBeanTargetSource
对象(如果您问我,这是不正确的(。但如果你这样做了
cart.toString();
您会看到差异,因为它实际上到达了基础Cart
对象。
根据您使用的范围和代理策略,所有这些都可能有所不同,但最终目标仍然可以实现。