axis2开发webservice之跨服务对话(Session)管理

axis2开发webservice之跨服务会话(Session)管理

         之前学习了同一服务中的session管理点击打开链接,今天来看一下跨服务的session管理,本来昨天晚上把服务器端都写好了,只剩下客户端的代码了,无奈,下班了,只好今天早上接着写了,也好就当是复习了。

        对于一个复杂的系统,不可能只有一个WebService服务,例如,至少会有一个管理用户的WebService(用户登录和注册)以及处理业务的WebService。象这种情况,就必须在多个WebService服务之间共享会话状态,也称为跨服务会话(Session)管理。实现跨服务会话管理与实现同一个服务的会话管理的步骤类似,但仍然有一些差别,实现跨服务会话管理的步骤如下:

实现跨服务的Session管理需要如下三步:

1. 使用MessageContextServiceGroupContext获得与设置key-value对。

2. 为要进行Session管理的WebService类所对应的<service>元素添加一个scope属性,并将该属性值设为application

3. 在客户端使用setManageSession(true)打开Session管理功能。

从上面的步骤可以看出,实现跨服务会话管理与实现同一个服务的会话管理在前两步上存在着差异,而第3步是完全一样的。下面是一个跨服务的会话管理的实例。在这个例子中有两个WebService类:LoginServiceSearchService,代码如下:

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);
		}
	}
}


在执行上面的代码后,将输出如下的信息:

axis2开发webservice之跨服务对话(Session)管理

如果将scope属性值改成transportsession,我们看看会输出什么!

第一:改变loginService的

axis2开发webservice之跨服务对话(Session)管理

     正常输出,也就是说loginService这个服务只能在同一个服务中起作用,在这里我们只是调用了登陆服务,所以没影响。

第二:改变searchService的

axis2开发webservice之跨服务对话(Session)管理

       居然还是正常输出,不对啊,如下代码需要跨服务的

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的问题,如下是官方文档

Transport Session Scope
In the case of a Transport session, Axis2 uses transport-related session management techniques to manage session. As an example, in the case of HTTP, it uses HTTP cookies to manage the session. The lifetime of the session is controlled by the transport, not by Axis2; Axis2 stores the service context and serviceGroupContext in the transport session object so that the service can access those contexts as long as the session lives.
One of the key advantages of the Transport session over other sessions is that you can talk to multiple service groups within one transport session.In a SOAP session, you don't have a way to communicate between two service groups, but with the transport session you have that capability. In this case, the number of service instances created depends on the number of transport sessions created.
Deploying a service in a transport session requires you to change services.xml as follows:
<service name="foo" scope="transportsession">
</service>
If you are using Axis2 nightly builds or planning to use them the next version, deploying a service in a transport session requires additional changes to axis2.xml. That is mainly to improve the memory usage; otherwise, whether you deploy the service in a transport session or not Axis2 tries to create a session object at the transport level; with these changes, it will not create unnecessary objects. To manage the transport-level session, you need to set the manageTransportSession parameter value to true in axis2.xml:

看到这段话的时候我才感觉到transportsession不仅是单个服务那么简单的。

 

至于ServiceGroupContext和ServiceContext,我查了一下API文档

axis2开发webservice之跨服务对话(Session)管理

可以看出来他们都是继承自同一个类,而这个抽象类的setProperty()方法如下,

axis2开发webservice之跨服务对话(Session)管理

从这里我们可以看到这个方法是用来存储值的,至于存储的值的访问权限,我们只有搞清楚ServiceGroupContext和ServiceContext才能知道。

下面是ServiceContext的介绍

axis2开发webservice之跨服务对话(Session)管理

axis2开发webservice之跨服务对话(Session)管理

 

在这里我们看到它的生命周期是不明确的,不推荐使用,而且其构造方法是可外部化的,关于这个问题,可以查看这篇文章点击打开链接

 

下面是ServiceGroupContext的介绍

 

axis2开发webservice之跨服务对话(Session)管理

其实到这里我还是没多大明白ServiceGroupContext和ServiceContext的主要区别,于是我又看了MessageContext,结果又多了一个疑惑

axis2开发webservice之跨服务对话(Session)管理
为什么MessageContext只持有ServiceGroupContext,而没有提及ServiceContext呢?

真是一波未平一波又起,看来还需要大家的智慧了,如果以上的这几个问题有懂的高手,还请留言解决一下。