之前学习了同一服务中的session管理点击打开链接,今天来看一下跨服务的session管理,本来昨天晚上把服务器端都写好了,只剩下客户端的代码了,无奈,下班了,只好今天早上接着写了,也好就当是复习了。
对于一个复杂的系统,不可能只有一个WebService服务,例如,至少会有一个管理用户的WebService(用户登录和注册)以及处理业务的WebService。象这种情况,就必须在多个WebService服务之间共享会话状态,也称为跨服务会话(Session)管理。实现跨服务会话管理与实现同一个服务的会话管理的步骤类似,但仍然有一些差别,实现跨服务会话管理的步骤如下:
实现跨服务的Session管理需要如下三步:
1. 使用MessageContext和ServiceGroupContext获得与设置key-value对。
2. 为要进行Session管理的WebService类所对应的<service>元素添加一个scope属性,并将该属性值设为application。
3. 在客户端使用setManageSession(true)打开Session管理功能。
从上面的步骤可以看出,实现跨服务会话管理与实现同一个服务的会话管理在前两步上存在着差异,而第3步是完全一样的。下面是一个跨服务的会话管理的实例。在这个例子中有两个WebService类:LoginService和SearchService,代码如下:
package crossSession;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.ServiceGroupContext;
public class LoginService
{
public boolean login(String username, String password)
{
if("bill".equals(username) && "1234".equals(password))
{
// 第1步:设置key-value对
MessageContext mc = MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc = mc.getServiceGroupContext();
sgc.setProperty("login", "成功登录");
return true;
}
else
{
return false;
}
}
public String getLoginMsg()
{
// 第1步:获得key-value对中的value
MessageContext mc = MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc = mc.getServiceGroupContext();
return (String)sgc.getProperty("login");
}
}
package crossSession;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.ServiceGroupContext;
public class SearchService
{
public String findByName(String name)
{
// 第1步:获得key-value对中的value
MessageContext mc = MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc = mc.getServiceGroupContext();
if (sgc.getProperty("login") != null)
return "找到的数据<" + name + ">";
else
return "用户未登录";
}
}
services.xml文件中的配置代码如下:
<serviceGroup>
<!-- 第2步:添加scope属性,并设置属性值为application -->
<service name="loginSession" scope="application">
<description>
登录服务
</description>
<parameter name="ServiceClass">
crossSession.LoginService
</parameter>
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</messageReceivers>
</service>
<!-- 第2步:添加scope属性,并设置属性值为application -->
<service name="searchSession" scope="application">
<description>
搜索服务
</description>
<parameter name="ServiceClass">
crossSession.SearchService
</parameter>
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
class="org.apache.axis2.rpc.receivers.RPCMessageReceiver" />
</messageReceivers>
</service>
</serviceGroup>
第3步与点击打开链接一文中介绍的方法类似。
下面是使用两个stub类的对象实例访问上面实现的两个WebService的客户端代码:(由于是两个service,所以要分别实现两个stub类)
package crossSession;
import java.rmi.RemoteException;
public class LoginSearchStubClient {
public static void main(String[] args) throws RemoteException {
// TODO Auto-generated method stub
LoginSessionStub lss = new LoginSessionStub();
LoginSessionStub.Login login = new LoginSessionStub.Login();
LoginSessionStub.GetLoginMsg glm = new LoginSessionStub.GetLoginMsg();
login.setUsername("bill");
login.setPassword("1234");
if(lss.login(login).local_return){
System.out.println(lss.getLoginMsg(glm).get_return());
SearchSessionStub sss = new SearchSessionStub();
SearchSessionStub.FindByName fbn = new SearchSessionStub.FindByName();
fbn.setName("bill");
System.out.println(sss.findByName(fbn).local_return);
}
}
}
在执行上面的代码后,将输出如下的信息:
如果将scope属性值改成transportsession,我们看看会输出什么!
第一:改变loginService的
正常输出,也就是说loginService这个服务只能在同一个服务中起作用,在这里我们只是调用了登陆服务,所以没影响。
第二:改变searchService的
居然还是正常输出,不对啊,如下代码需要跨服务的
if (sgc.getProperty("login") != null)
return "找到的数据<" + name + ">";
else
return "用户未登录";
这是怎么回事呢,难道问题在这里?
// 第1步:获得key-value对中的value
MessageContext mc = MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc = mc.getServiceGroupContext(); //ServiceGroupContext而不是ServiceContext?
//ServiceGroupContext与scope冲突?
好吧,既然冲突,那咱们就一个一个的试,结果更加出乎意料,把ServiceGroupContext改成ServiceContext,居然还是正常输出,什么情况?
这让我开始怀疑这个程序是不是跨session的,不会是披着跨session的外衣吧,继续研究!
先看一下scope中transportsession的问题,如下是官方文档
</service>
看到这段话的时候我才感觉到transportsession不仅是单个服务那么简单的。
至于ServiceGroupContext和ServiceContext,我查了一下API文档
可以看出来他们都是继承自同一个类,而这个抽象类的setProperty()方法如下,
从这里我们可以看到这个方法是用来存储值的,至于存储的值的访问权限,我们只有搞清楚ServiceGroupContext和ServiceContext才能知道。
下面是ServiceContext的介绍
在这里我们看到它的生命周期是不明确的,不推荐使用,而且其构造方法是可外部化的,关于这个问题,可以查看这篇文章点击打开链接
下面是ServiceGroupContext的介绍
其实到这里我还是没多大明白ServiceGroupContext和ServiceContext的主要区别,于是我又看了MessageContext,结果又多了一个疑惑
为什么MessageContext只持有ServiceGroupContext,而没有提及ServiceContext呢?
真是一波未平一波又起,看来还需要大家的智慧了,如果以上的这几个问题有懂的高手,还请留言解决一下。