Axis2的會話管理(譯)

    本文是對《Axis2 Session Management》的翻譯,所依據的英文在http://www.developer.com/services/article.php/3620661/Axis2-Session-Management.htm。以下是翻譯內容。
    Web服務有着很大的需求,很多人進入了Web服務這一領域,其結果是人們需要Web服務具有更多的特性,以便使用Web服務可以完成任何事情。但Web服務從設計上來說是沒有狀態的。在Web服務世界起初的時候是沒有管理會話的概念的,但是現在形勢改變了:沒有會話管理,開發者是無法開發出高級的應用程序的。一個很好的例子是銀行系統,您登錄進入系統,然後取錢,最後退出登錄。
    如果我們把這一場景映射到Web服務:
  • 首先,用戶登錄進自己的賬戶(調用登錄方法)
  • 用戶取錢(在他的賬戶上調用一些操作)
  • 用戶退出登錄(完成事務)
    您可以很容易的看出上述3個操作是相互關聯的,同一個用戶進行3個調用操作。所以,這意味着需要有地方來跟蹤用戶,另外有地方在用戶調用方法期間跟蹤用戶數據。這也就暗含了需要會話管理。
    當開發高級應用程序時,我們必須打破現有的規則;否則,沒有人能夠開發出真正的Web應用程序。雖然Web服務本質上是無狀態的,但是需要在Web服務之上增加一層會話管理的功能。
    Axis2的無狀態本質
    Axis2的優秀設計原則之一是保持邏輯和狀態的分離,所以它沒有組件需要維護會話,實際上也是這樣做的。在Axis2的處理程序中,傳輸部分,甚至Aixs引擎部分都是無狀態的。因此,對Axis2來說多個實例和一個實例是沒有區別的。
    作爲最佳實踐,處理程序或傳輸部分不應該保持任何實例變量(如果可能會變化的話),因爲那樣會打破Axis2無狀態的本質。所以,如果處理程序或傳輸部分需要有狀態的方式,正確的做法是在需要的時候保存狀態和Axis2的狀態層次,而不是保持實例變量。
    Axis2的會話類型
    像上面提到的,企業級Web服務無法得到認可除非引在Web服務引擎中入了會話概念。換種說法,因爲存在不需要維持會話的Web服務,讓每種Web服務引擎都支持會話管理這樣的說法是不對的。一個很好的例子是Google搜索服務和Google拼寫檢查服務。
    會話管理的直接影響是佔用內存空間的上升和性能的降低,所以您需要一個折中:您的服務是否要支持會話並提供狀態。Axis2是定位於企業級Web服務引擎的,所以它必須提供會話管理。
    有幾種類型的會話,它們的生命週期是各不相同的。有些會話存在幾秒鐘,而有些會話的生命週期和系統一樣長。Axis2設計爲支持4種類型會話,它們存在很多差別,希望您能夠使用以下4種會話類型開發出各種Web服務。
  • Request
  • SOAPSession
  • Application
  • Transport
    Axis2的上下文層次結構
    在深入討論Axis2的會話之前,理解Axis2的各種上下文是很有幫助的。如上所述,Axis2保持邏輯和狀態的分離,上下文是保存狀態的地方。在Axis2中有5種類型的上下文:
  • ConfigurationContext:整個系統運行時的表述,爲了啓動Axis2系統需要有一個配置上下文。配置上下文與系統的生命週期是一樣的,在這裏保存一些狀態(配置項)能夠一直有效(直到系統關閉)。
  • ServiceGroupContext:在Axis2中,可以在一個服務組中部署多個服務。在運行時,有一個或多個服務組(依賴於組的會話範圍)上下文在會話範圍內保存組的狀態。
  • ServiceContext:表述一個服務的運行時狀態,其生命週期與會話的生命週期相同。依賴於所對應服務的會話範圍,存在一個或多個服務上下文。
  • OperationContext:表述MEP(Message Exchange Patterns,消息交換格式)的生命週期。操作上下文的生命週期通常短於服務上下文的生命週期。
  • MessageContext:表述所輸入消息的生命週期。如果給定執行鏈中的兩個處理程序想共享數據,最好的方法是把他們存在消息上下文中。一個操作上下文可能有多個消息上下文。
    與會話範圍無關,當會話開始和結束時,Axis2會通知服務的實現類,但是需要在服務的實現類中增加兩個方法。
public void init(ServiceContext serviceContext) {
}

public void destroy(ServiceContext serviceContext) {
}
    除此之外,當服務接收到一個請求時,它會傳入相應的操作上下文作爲參數進行通知。如果服務想訪問輸入消息的上下文或輸入的SOAP消息,可以在服務的實現類中加入以下方法來做到這一點,在真正的方法調用之前調用這一方法。
public void setOperationContext(OperationContext operationContext) {
}
    請求會話範圍(Request Session Scope)
    請求會話是Axis2默認的會話類型,部署服務時沒有指定會話管理的內容,服務會被部署爲請求會話類型。這種會話的生命週期被限定在方法調用的生命週期之內,或者請求的處理時間內。所以,當部署服務爲請求範圍的服務時,是沒法管理會話的;這與沒有會話是一樣的。
    一旦把服務部署爲請求會話範圍的服務時,每個服務的實現類就會準備建立服務實例。例如以請求範圍的方式建立了一個名爲“foo”的服務,如果客戶端調用了10次,就會有這個服務實現類的10個實例。如果想顯式的指定服務的會話範圍,可以在services.xml中的service標籤中增加一個scope屬性,如下:
<service name="foo" scope="request">
</service>
    即使把服務部署爲請求範圍內的,在Axis2中也有一些方法管理會話。一種方法是在Axis2的全局運行時(配置上下文)中保存狀態,在需要的時候獲取它。
    SOAP會話範圍(SOAP Session Scope)
    SOAP會話的生命週期比請求會話的稍長,以SOAP會話的方式部署服務需要修改services.xml。管理SOAP會話需要客戶端和服務都能識別會話,換句話說,客戶端訪問相同會話需要傳輸會話相關的數據,服務需要以會話相關的數據來驗證用戶。
    管理SOAP會話,客戶端需要在SOAP頭中增加名爲“serviceGroupId”的參數。SOAP會話不僅提供一個服務調用的會話,還提供一個服務組中多個服務的會話。只要在同一個SOAP會話中,可以在服務上下文中管理服務相關的數據;如果想在組中多個服務中共享數據,可以使用服務組上下文。
    以SOAP會話的方式部署了服務,當客戶端第一次訪問服務的時候,Axis2會產生“serviceGroupId”,並在wsa:ReplyTo中以引用參數的方式向客戶端傳輸:
<wsa:ReplyTo>
  <wsa:Address>
  http://www.w3.org/2005/08/addressing/anonymous
  </wsa:Address>
  <wsa:ReferenceParameters>
    <axis2:ServiceGroupId xmlns:axis2=
      "http://ws.apache.org/namespaces/axis2">
        urn:uuid:65E9C56F702A398A8B11513011677354
    </axis2:ServiceGroupId>
  </wsa:ReferenceParameters>
</wsa:ReplyTo>
    如果客戶端想保持在同一個會話內,它要複製那個引用參數,並在第二次調用服務的時候傳回服務器。只要客戶端傳輸了正確的“serviceGroupId”,它就會在同一個會話內,服務也可以維護會話相關的數據。與請求會話不同,SOAP有默認的失效期,如果客戶端超過30秒沒有連接服務,會話就會過期。如果客戶端發送了過期的“serviceGroupId”,會得到Axis錯誤。
    管理SOAP會話需要銜接服務端和客戶端的對應模塊。部署服務爲SOAP會話方式需要以如下方式修改services.xml:
<service name="foo" scope="soapsession">
</service>
    傳輸會話範圍(Transport Session Scope)
    在傳輸會話方式下,Axis2以傳輸相關的會話管理技術來管理會話。例如,在HTTP協議下,以HTTP cookies的方式來管理會話。會話的生命週期是由傳輸來控制的,而不是Axis2;Axis2在傳輸會話內保存服務上下文和服務組上下文,所以在會話生命期內服務都可以訪問這些上下文。
    傳輸會話的主要優勢是在一個會話內與多個服務組交互。在SOAP會話中,無法在兩個服務組間進行交互,而在傳輸會話中就可以。這種情況下,服務實例的數量取決於傳輸會話的數量。
    部署服務爲傳輸會話方式需要以如下方式修改services.xml:
<service name="foo" scope="transportsession">
</service>
    如果打算使用Axis2,以傳輸會話方式部署服務需要對axis2.xml做些修改。這主要是爲了提高內存的使用率;否則,無論是否以傳輸會話方式部署服務,Axis2都會在傳輸的級別建立會話對象;有了這些變化,Axis就不會創建無用的對象了。爲了管理傳輸級別的會話,需要在axis2.xml中設置“manageTransportSession”參數爲“true”:
<parameter name="manageTransportSession"
    locked="false">true</parameter>
    應用範圍(Application Scope)
    應用範圍的會話與其他會話方式相比具有最長的生命週期,應用會話的生命週期與系統的生命週期一樣長。如果以應用範圍會話的方式部署服務,只會有服務的一個實例,並且這個服務只有一個服務上下文。在Axis2中,如果考慮內存佔用,並且不想管理會話,一個好的方法是把服務部署爲應用範圍的。
    當把服務部署爲應用範圍的會話方式時,客戶端不需要傳送額外的數據以使用同一個會話。部署服務爲應用範圍會話方式需要以如下方式修改services.xml:
<service name="foo" scope="application">
</service>
    服務客戶端管理會話
    客戶端管理會話需要做一些工作。如上所述,客戶端如果想在SOAP會話和傳輸會話方式下保持在同一個會話中,需要傳輸一些會話相關的數據。對SOAP會話來說,需要複製所需的引用參數;對傳輸會話來說,需要訪問傳輸以複製和發送cookies。
    爲了簡化開發,Axis2有內置的管理會話的功能,在客戶端設置一個標誌就可以了。這樣,只要使用同一個客戶端,就會往服務端發送會話相關的數據。所以,如果想保持在同一個會話內,最主要的一點就是使用同一個客戶端調用服務。
    如果想保持在同一個會話內,可以用以下的方式創建服務客戶端,並且重用客戶端對象調用服務。
Options options = new Options();
options.setManageSession(true);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
    一旦按照如上方式創建了服務客戶端,如果服務部署爲SOAP會話方式,客戶端會複製“serviceGroupId”並在第二次調用的時候上傳服務端;如果服務器是發送的會話id,例如HTTP cookies,客戶端就會複製服務上下文(在客戶端)並在第二次調用的時候發送給服務器。
    總結
    無狀態是Web服務的主要特性之一,但這對高級Web服務開發來說是一個限制。使用Web服務開發企業級的應用並不容易,除非有一個會話管理層。Axis2有4中會話類型以解決企業級服務開發的問題。
附英文原文:
Web services are in high demand and a large number of players have entered the web service arena. As a result of this, users are looking for more and more features, and they are trying to do everything by using Web services. By design, Web services are said to be stateless. There was no notion of managing sessions in the Web service world, but now this has changed and users cannot develop an advanced application without managing state. A good example would be banking applications where you log in into the system, withdraw money, and log, out.
If we try to map that into a Web service:
  • First, the user logs in into your account (invoking a login method)
  • The user withdraws money (invoking some operation on his account)
  • The user logs out (completing the transaction).
You easily can understand that the three operations stated above are interrelated, and the same user does all three invocations. So, it means that someone needs to keep track of the user, and another has to keep track of the user data throughout methods invocation. This implies the need for session management.
When it comes to advanced applications, we have to break the rules; otherwise, no one can implement real Web applications. As a result, even though Web services are stateless by nature, upi need to add a layer above it to provide session management.
The Stateless Nature of Axis2
One of the good design principles of Axis2 is that it keeps logic and states separately, so none of its components are needed to maintain session and they don't maintain sessions. In Axis2 handlers, transports and even AxisEngine are said to be stateless; therefore, there is no difference between having multiple instances or one instance of them.
As a best practice, a handler or transport should not keep any instance variable (if it is likely to be changed), because that breaks the stateless nature of Axis2. So, if the handler or transport wants to act in a stateful manner, the correct way is to store the state and Axis2 state hierarchy and use it whenever necessary, rather than keeping instance variable.
Types of sessions in Axis2
As mentioned above, an enterprise web service cannot sustain itself unless the session concept burns into Web service engines. In other words, it is wrong to say that each and every SOAP web service engine should maintain sessions because you can have services that do not require maintaining sessions. A good example could be a Google search service and a Google spell checker service.
Managing sessions directly causes an increase of the memory footprint and to slow down performance, but you need to have a compromise: whether or not you support the session and provide state full service development. Axis2 is meant to be an enterprise Web service engine, so it has to support session management.
When sessions are considered, there can be different types of sessions as well, and the lifetime of the session may vary from one to another. Some sessions last a few seconds whereas others last the system lifetime. Axis2 architecture has been designed to support four types of sessions. There are a few differences from one to another; hopefully you can develop any kind of Web service by using the following four types of session scope.
  • Request
  • SOAPSession
  • Application
  • Transport
Axis2 context hierarchy
It is useful to understand the types of contexts in Axis2 before discussing types of session in depth. As mentioned above, Axis2 keeps logic and states separately, so contextS are there to store the states. There are five types of contexts in Axis2:
  • ConfigurationContext:The runtime representation of THE whole system, to start Axis2 system you need to have A configuration context. The lifetime of configuration context will be the lifetime of the system, so if you store some state (a property) it will last forever (until system shutdown).
  • ServiceGroupContext:In Axis2, you can deploy multiple services together as a service group. At runtime, there will be one or more service group contexts (depending on the session scope of the group) to keep states of the group throughout the session.
  • ServiceContext:Will represent the runtime of one service; the context lifetime will be the lifetime of the session. There can be one or many service contexts in the system depending on the session scope of the corresponding service.
  • OperationContext:This context represents the lifetime of a MEP (Message Exchange Patterns). The lifetime of the operation context is usually less than the lifetime of the service context.
  • MessageContext:The lifetime of an incoming message is represented by the message context. If two handlers in a given execution chain want to share data, the best way is to store them in message context. One operation context may have many message contexts.
Irrespective of the session scope, when the session start up and when it finishes, Axis2 will notify the service implementation class, but you have to add two additional methods to your service implementation class.
public void init(ServiceContext serviceContext) {
}

public void destroy(ServiceContext serviceContext) {
}
In addition to that, whenever a service receives a request, it will notify by passing the corresponding OperationContext as an argument. So, if the service wants to access an incoming message's context or an incoming SOAPMessage, he can do that by just adding the following method to the service implementation class; this method will be called before the actual method is called.
public void setOperationContext(OperationContext operationContext) {
}
Request session scope
Request session scope is the default session in Axis2. When you deploy a service without knowing anything about session management, your service will be deployed in the requested session scope. The lifetime of this session is limited to the method invocation's lifetime, or the request processing time. So, when you deploy a service in request scope, you don't have a way to manage session; it is the same as though you don't have a session at all.
Once you deploy a service in request session scope for each and every invocation service, the implementation class will be created. Say you have deploy a service called "foo" in request scope; if a client invokes the service 10 times, there will be 10 instances of the service implementation class. If you want to specify the scope explicitly, you still can do that by adding a scope attribute to the service element in services.xml as follows:
<service name="foo" scope="request">
</service>
Even if you deploy a service in a request scope, there are many ways of managing sessions in Axis2. One way is to store the state in Axis2' global runtime (configuration context) and retrieve it whenever necessary.
SOAP Session Scope
SOAP session scope has a slightly longer lifetime than a request session, and deploying a service in a SOAP session is required to change services.xml. Managing a SOAP session requires both the client and service to aware of the sessions; in other words, the client has to send the session-related data if he wants to access the same session and the service has to validate the user by using session-related data.
To manage a SOAP session, a client has to send an addition reference parameter in the SOAP header; it is named the serviceGroupId parameter. The SOAP session provides a way to manage the session not only for a single service invocation but also for multiple services in a service group. As long as you are in the same SOAP session, you can manage service-related data in a service context; if you want to share data across other services in the group, you can use serviceGroupContext.
When you deploy a service in SOAP session and when a client tries to access the service in the first time, Axis2 will generate serviceGroupId and send that to the client as a reference parameter in wsa:ReplyTo, as shown below:
<wsa:ReplyTo>
  <wsa:Address>
  http://www.w3.org/2005/08/addressing/anonymous
  </wsa:Address>
  <wsa:ReferenceParameters>
    <axis2:ServiceGroupId xmlns:axis2=
      "http://ws.apache.org/namespaces/axis2">
        urn:uuid:65E9C56F702A398A8B11513011677354
    </axis2:ServiceGroupId>
  </wsa:ReferenceParameters>
</wsa:ReplyTo>
If the client wants to live in the same session, he has to copy that reference parameter and send it back to the server when he invokes the service the second time. As long as a client sends the valid serviceGroupId, he can use the same session, and the service can maintain the session-related data. Unlike a request session, a SOAP session has a default timeout period, so if the client does not touch the service for 30 seconds, the session will expire, and if the client sends the old serviceGroupId, he will get an AxisFault too.
Managing a SOAP session requires you to engage addressing modules on both the server side and client side. Deploying a service in a SOAP session requires you to change services.xml as follows:
<service name="foo" scope="soapsession">
</service>
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:
<parameter name="manageTransportSession"
    locked="false">true</parameter>
Application Scope
Application scope has the longest lifetime compared to others; the lifetime of the application session is equal to the lifetime of the system. If you deploy a service in application scope, there will be only one instance of that service and obviously there will be only one service context for that service. In the Axis2 world, if you consider the memory footprint and if you don't want to manage the session, the good candidate is to deploy the service in application scope.
When you deploy a service in application scope, a client does not need to send any additional data to use the same session. To deploy a service in application scope, you need to change axis2.xml as shown below:
<service name="foo" scope="application">
</service>
Managing the session using the service client
Managing the session on the client side involves bit of a work. As mentioned above, both in a SOAP session and Transport session a client has to send the session-related data if he wants to live in the same session. Maybe he can do that for a SOAP session by coping with required reference parameters, but with a Transport session a user must get access to the transport to copy and send cookies.
To make life easier, Axis2 has the built-in capability of managing sessions in the client session by just setting a flag. Then, depending on the service side session, it will send the corresponding data as long as you use the same service client. So, the main requirement is to use the same service client to invoke the service if you want to live in the same session.
If you want to live in the same session, you can create service client as shown below and re-use the created service client object to invoke the service.
Options options = new Options();
options.setManageSession(true);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
Once you create the service client as shown above, if the service deploys in a SOAP session it will copy the serviceGroupId and send that from the second invocation onwards. If the server sends the session id, such as HTTP cookies, it will copy that to the service context (on the client side) and send it back to the server when the client invokes the service for a second time.
Summary
The stateless nature is one of the main characteristics of Web services, but it is a limitation for advanced Web services developers. Developing an enterprise-level application using Web services is not easy unless you have a session management layer. Axis2 has four levels of sessions to address enterprises-level Web service development issues.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章