BaseStateManagerService有一个类型为Map的成员变量m_httpSessions,以Thread对象为key, HttpSession对象为值。HttpSession对象中属性的key 是前面DefaultJetspeedRunData的StateEntry类型的session数据操作接口的key,属性的值为StateEntry 对象。StateEntry对象的成员变量m_key保存操作接口的key,成员变量m_map是一个Map对象,以后面我们要讲的 setAttribute方法的name参数为 key,value参数为值。
3.4.3.2 初始化
下面的顺序图是一个简图,主要用于解释BaseStateManagerService的成员变量m_httpSessions的映射如何被填充和清除。
Turbine是一个servlet,其doGet方法是jetspeed系统的入口。
填充
Turbine请求JetspeedRunDataService生成RunData对象,JetspeedRunDataService调用 HttpServiceRequest的getSession(true)方法获取与当前请求对应的httpSession对象(以true为参数, getSession在当前session无效时会返回一个新的httpSession对象,否则返回先前请求的httpSession对象), JetspeedRunDataService接着调用JetspeedHttpStateManagerService的 setCurrentContext(httpSession对象)方法,这个方法会以当前的Thread为key,参数httpSession对象为值填充BaseStateManagerService的成员变量m_httpSessions。
清除
doGet方法填充了m_httpSessions,并作了好多事情之后,在即将退出之前调用了JetspeedRunDataService的 putRunData(data)方法,这个方法再调用JetspeedHttpStateManagerService的 clearCurrentContext()方法删除BaseStateManagerService的成员变量m_httpSessions中以当前 Thread为key的Map项。
下图显示了m_httpSessions对象经过初始化后的内存状态快照,体现了m_httpSessions对象保留的Thread-〉HttpSession的映射关系。
3.4.3.3 属性操作
当DefaultJetspeedRunData通过session操作接口获取SessionState之后,其它就可以使用SessionState对象的成员方法操作状态属性了。这两个方法是:
public void setAttribute( String name, Object value );
public void removeAttribute( String name );
在从RunData对象处获取sessionState对象后,jetspeed代码可以调用这个对象的属性操作方法。
setAttribute(name,value)操作的大概步骤是:
(1) 主要步骤:
1.1sessionState对象利用自己的key,结合参数name,value调用JetspeedHttpStateManagerService的setAttribute(key,name,value)方法;
1.1.1JetspeedHttpStateManagerService调用自己的getState(key)方法在参数key的帮助下获取保存在当前线程session中的StateEntry对象的m_map变量,这个过程由1.1.1.1-1.1.1.4组成;
1.1.2得到StateEntry对象的m_map变量后,JetspeedHttpStateManagerService接着先处理m_map中的先前的参数name对应的属性值,再设置参数name对应的属性值新值为参数value。
(2) 候选步骤:
1.1.1a 如果session中没有相应的StateEntry对象,则先生成并往一个session中加入一个。
getAttribute(name)操作的大概步骤是:
(1) 主要步骤:
2.1sessionState对象利用自己的key,结合参数name调用JetspeedHttpStateManagerService的getAttribute(key,name)方法;
2.1.1JetspeedHttpStateManagerService调用自己的getState(key)方法在参数key的帮助下获取保存在当前线程session中的StateEntry对象的m_map变量;
2.1.2得到StateEntry对象的m_map变量后,JetspeedHttpStateManagerService接着调用m_map对象的get(name)方法获取属性值。
下图体现了这些方法执行后HttpSession对象保留的key-> StateEntry对象以及StateEntry对象的Name->Value的映射关系。
3.5 修改建议
(1) 实现数据库形式的repository。根据前面的集群需求第五条,必须把repository数据库化才能使得集群下的各个jetspeed的资源视图相同。
(2) StateEntry。根据前面的集群需求第一条,必须让StateEntry实现Serializable接口。目前StateEntry是一个内部类,为了让JVM的Serializer设施能顺利创建StateEntry对象,最好把其public化。
(3) setAttribute要重设session属性。根据前面的集群需求第二条,session对象的setAttribute是导致复制的引子,我们必须在改变session属性后调用session对象的setAttribute方法重置session属性,如下图所示。
虽然Jetspeed中这样模式的代码如下:
更改JetspeedHttpStateManagerService的setAttribute方法。
对下面类中的doXXX方法按照这个模式进行修改。
controllers.MultiColumnControllerAction;
portlets.CustomizeSetAction;
controllers.RowColumnControllerAction;
注意StateEntry中的值的序列性。
4 总结可以这样说,目前的jetspeed在设计和实现时没有考虑集群环境下的运行情况,本文的分析突出了jetspeed支持集群的主要症结、但不一定完善,甚至有不正确的地方,另外一个主要内容是分析jetspeed保存在session对象中的数据。希望本文有助于大家加深对集群的理解,有助于提醒大家在设计和开发软件系统时"keep clustering in mind"。