简体   繁体   English

HttpSession-s之间共享的Spring Session Bean

[英]Spring session bean shared between HttpSession-s

I'm trying to undestand session beans in Spring. 我试图在春季不理解会话bean。 The book I'm reading says, about them, that: 我正在阅读的书对它们说:

the bean is created when needed and stored in the javax.servlet.http.HttpSession. 该bean在需要时创建,并存储在javax.servlet.http.HttpSession中。 When the session is destoyed so is the bean instance. 当会话被保存时,bean实例也被保存。

I tried with the following example: 我尝试使用以下示例:

The bean: 豆:

package com.at.test.web;

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

The bean definition: Bean的定义:

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

The controller: 控制器:

@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";
  }
}

This is what happens on Tomcat startup: 这是在Tomcat启动时发生的情况:

Cart::<init> with hashCode 970109301

I think Spring need this instance in order to create the CGLIB proxies. 我认为Spring需要此实例才能创建CGLIB代理。 Anyway, I'm not that sure. 无论如何,我不确定。

After the startup, I use two different browsers to have two different HttpSession. 启动后,我使用两个不同的浏览器来拥有两个不同的HttpSession。 The result, when the controller is invoked, is: 调用控制器时,结果为:

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

The cart instance seems to be shared between HttpSession-s, but I was expecting two instances of Cart. cart实例似乎在HttpSession-s之间共享,但是我期望有两个Cart实例。

The same if I let the bean implements an interface, use annotation-driven approch and component scan: 如果我让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());
    }
}

Am I missing something? 我想念什么吗? Did I misunderstood the meaning of session bean? 我是否误解了会话bean的含义?

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

The Cart instance that gets injected into the HomeController instance is only a proxy that delegates method calls to the "real" instance. 注入到HomeController实例中的Cart实例仅仅是将方法调用委托给“真实”实例的代理。 The Cart class itself has no own method or state yet, so you won't notice any difference between sessions, of course. Cart类本身还没有自己的方法或状态,因此您当然不会注意到会话之间的任何区别。

There's a lot of proxying and delegation going on. 正在进行很多代理和委派。

This field 这个领域

@Autowired 
private Cart cart;

where Cart is session scoped will be proxied as you can see in your logs 如您在日志中所见,将在会话范围内对Cart进行代理

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

But this proxy is not wrapping a Cart object. 但是此代理未包装Cart对象。 It is wrapping a SimpleBeanTargetSource which takes care of getting a Cart bean from the BeanFactory . 它包装了一个SimpleBeanTargetSource ,它负责从BeanFactory获取Cart Bean。

Your bean definition attaches a SessionScope object which is responsible for checking your HttpSession through a static ThreadLocal field in RequestContextHolder . 您的bean定义附加一个SessionScope对象,该对象负责通过RequestContextHolderstatic ThreadLocal字段检查HttpSession When request is made to get a bean from the BeanFactory , it will delegate the action to the SessionScope object which will check the HttpSession , use the one there if it exists or create and register a new one if it doesn't. 当请求从BeanFactory获取一个bean时,它将把动作委托给SessionScope对象,该对象将检查HttpSession ,如果存在则使用HttpSession ,否则创建并注册一个新的HttpSession

You don't notice this with your test because 您在测试中没有注意到这一点,因为

cart.hashCode()

delegates to the SimpleBeanTargetSource object (incorrectly, if you ask me). 委托给SimpleBeanTargetSource对象(如果您问我的话,则是错误的)。 But if you did 但是如果你做到了

cart.toString();

you would see the difference as that actually reaches the underlying Cart object. 您会看到实际到达基础Cart对象的差异。


Depending on the scope and proxying strategy you use, all this may be different, but the end goal is still achieved. 根据您使用的范围和代理策略,所有这些可能有所不同,但最终目标仍然可以实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM