昨天加班在搞一个关于session的问题,有兴趣的童鞋可以去这里观望一下。

总之除了吃惊外就是感觉手脚束缚!现在只能彻底放弃使用默认的session机制了,不知道这算是好事儿还是坏事儿。

现在的思路是这样的:

  1. 在Servlet过滤器中把ServletRequest对象替换为自己的Wrapper实例,在其中实现getSession()方法,返回我们自定义的HttpSession对象
  2. 我们实现一个继承了HttpSession接口的自定义会话类,用于第一步的返回,该自定义会话类提供接受sessionId参数获取会话数据的方法
  3. 通过拿在request对象中获取的sessionIdredis中取得对应的登录用户的信息:sessionUser对象;
  4. 在每次请求处理完后(过滤器最后一行代码)让自定义会话类把会话数据回写入redis,由于要持久化对象到redis中,所以要选择一个高效能的序列化与反序列化实现。

当然也可以再进一步优化,例如说最后一步,检查如果MySession对象没有被修改则不需要回写等。

说到现在,貌似和这篇文章的主题没有半毛钱关系的说~~表着急嘛,这不是要开始说了嘛!

上面的第三步提到,我们自定义的这个会话对象的生命周期应该为:每次请求。如果采用spring默认提供的singleton的话就乱套了,你懂的!

在和同事讨论上面的自定义会话机制的实现时,他叮嘱我说:

@Scope("request")作用域使用时要加上额外的参数(proxyMode)

不过并没有给我说清楚到底为啥。本着打破砂锅问到底的神经,我在GG和百度上搜索了一下,不知道是不是因为关键字写的不合理,总之并没有找到有用的中文资料,大多都是相互转载,而且讲的都是理论,并且用的也配置文件方式而非注解。

无奈只得翻墙查了一下,找到了一篇很好的文章,而且早在2010年就已经总结出来了,为啥国内社区的就没有呢?真的是我搜的方式不对么?

不扯淡了,文章中说:

Method Injection is useful in scenarios where you need to inject a smaller scope bean in a larger scope bean. For example, you have to inject a prototype bean inside an singleton bean , on each method invocation of Singleton bean. Just defining your bean prototype, does not create new instance each time a singleton bean is called because container creates a singleton bean only once, and thus only sets a prototype bean once.

大概意思是,当你把声明为相对范围小的作用域(例如:prototy)对象注入到相对范围大的作用域(例如:singleton)对象时,由于外层对象只会初始化一次,所以会导致内部注入的对象也只会被初始化一次。

道理十分的简单,就是因为这个原因,所以你有意把作用域定义为prototy的类可能并不是按照你认为的方式运作。

解决这个问题的方法有多种,比方说你可以使用Method Injection,而不是直接注入在类属性中,不过这就要求程序员在使用时需要特别对待这些类。

现在就是*proxyMode发挥作用的时候:

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")

这么写,就可以保证该类会按照你大脑中的方式使用了:每次使用都会重新初始化一个对象

源码就不去深究了。8~