Servlet在web services中起到很大的作用,負責(zé)解析soap文件(消息和附件封套),使用wsdl來校驗soap消息等。作為基本的編程是可以用servlet來解析soap消息,尤其是對于帶附件的soap消息,這樣做很透明,但是servlet不能作為Web服務(wù),當(dāng)然拓展的JAXM是可以做到的?,F(xiàn)在那些支持web services的項目都是通過底層上實現(xiàn)了servlet的功能,來完成HTTP+SOAP的通信,就不需要程序員考慮基于HTTP的SOAP消息的通信過程(不要有這樣的誤解,在java平臺上HTTP的通信的服務(wù)程序是servlet/jsp,而現(xiàn)在你不用servlet和jsp來通信,豈不是矛盾?事實不矛盾,記住是底層已經(jīng)實現(xiàn)了servlet功能,具體通信有底曾自己管理),直接上升到業(yè)務(wù)邏輯的服務(wù)編程。當(dāng)然有時也可以編寫解析SOAP消息的servlet,那就僅僅只是SOAP通信了(servlet無法作為服務(wù)來描述)。
下面根據(jù)配置文件,來說明一些底層與web services的關(guān)系:
回顧一下servlet的映射模式。我們知道,servlet是從javax.servlet.http.HttpServlet繼承的,在服務(wù)器端被載入JVM執(zhí)行,然后向客戶端輸出html流。
servlet的web.xml文件(位于 webapps/foo/WEB-INF目錄):
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
invoker servlet 其實是:org.apache.catalina.servlets.InvokerServlet
按類名提供小服務(wù)程序。例如,如果您調(diào)用 foo/servlet/HelloServlet,
invoker servlet將裝入該HelloServlet(如果它在其類路徑中的話)并執(zhí)行。
初看上面的web.xml,好像只給出了一個servlet映射,而沒有定義invoker servlet。
其實,invoker servlet 是在tomcat的conf目錄中的web.xml中定義的::
org.apache.catalina.servlets.InvokerServlet
所以,如果拋開Tomcat_HOME/conf/web.xml,我們這樣定義一個web.xml,似乎更能清楚的說明問題:
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
org.apache.catalina.servlets.InvokerServlet
即所有/servlet/* 模式的url,都會交給org.apache.catalina.servlets.InvokerServlet來處理。
或者說,所有/servlet/* 模式的url,其實都是調(diào)用InvokerServlet這個類,而InvokerServlet本身也是
一個servlet,它也是從 HttpServlet 繼承而來的。
這樣,我們自己的servlet就能夠通過特定的url執(zhí)行,即 /servlet/OurServlet。
當(dāng)然,如果你高興,可以定義任何的 url pattern,而不一定是 /servlet/*,這一點,正如我們后面
看到的Axis處理Soap消息的方法。
進一步,如果不想讓 InvokerServlet 在中間“搗鬼”,我們當(dāng)然可以直接定義自己的servlet:
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
com.foo.MyServlet
JSP也是一樣的道理,有了上面的分析,
看看Tomcat_HOME/conf/web.xml中的如下語句就可以JSP的處理方法了,這里就不再廢話了:
....
....
進入正題。
我們先來看部署Web Service的web.xml:
所有 /services/* 模式的 url 都會交給org.apache.axis.transport.http.AxisServlet處理,
AxisServlet當(dāng)然也是從HttpServlet繼承而來的。這就是為什么我們部署的Web服務(wù)在調(diào)用時都要在
服務(wù)名稱前加上 services/ 了。
可以說,AxisServlet是所有Web服務(wù)調(diào)用的入口。
那么AxisServlet在接手Web服務(wù)調(diào)用后都做了哪些工作呢?
客戶端用call.invoke()調(diào)用web服務(wù)用的是POST,所以入口是AxisServlet.doPost...
而不是AxisServlet.doGet...
先來看看AxisServlet的doPost函數(shù),這里只給出了關(guān)鍵語句及注釋:
/**
* Process a POST to the servlet by handing it off to the Axis Engine.
* Here is where SOAP messages are received
* @param req posted request
* @param res respose
* @throws ServletException trouble
* @throws IOException different trouble
*/
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
msgContext = createMessageContext(engine, req, res);//獲取客戶請求信息
engine.invoke(msgContext); //調(diào)用客戶端請求的服務(wù)
responseMsg = msgContext.getResponseMessage();//得到調(diào)用的返回結(jié)果
sendResponse(getProtocolVersion(req), contentType, res, responseMsg);//將結(jié)果送至客戶端
}
這樣一來,Web服務(wù)調(diào)用的來龍去脈就大致清楚了。。。
為了高清楚前面我們的三個url
http://192.168.0.1/test/services
http://192.168.0.1/test/services/sayHelloService?wsdl
http://192.168.0.1/test/services/sayHelloService?method=sayHelloTo&aname=everybody
是怎樣獲得輸出結(jié)果的,再來看看AxisServlet的doGet函數(shù),這里只給出了流程框架及注釋:
**
* Process GET requests. Because Axis does not support the GET-style
* pseudo execution of SOAP methods, this handler deals with queries
* of various kinds, not real SOAP actions.
*
* @todo for secure installations, dont stack trace on faults
* @param request request in
* @param response request out
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
//如果路徑為空,比如:http://localhost/wstk/services 或 http://localhost/wstk/services/*
if((pathInfo == null || pathInfo.equals("")) && !realpath.endsWith(".jws"))
{
//從server-config.wsdd文件中讀取所有部署的服務(wù)信息,向向客戶端列出所有部署的服務(wù),
//包括每個服務(wù)可調(diào)用的方法。
}else
//如果路徑不為空,比如:http://localhost/wstk/services/sayHelloService
if(realpath != null)
{
//如果請求wsdl,比如:http://localhost/wstk/services/sayHelloService?wsdl
if(wsdlRequested)
{
//創(chuàng)建sayHelloService的WSDL文件并傳送至客戶端
} else
//這里是利用url調(diào)用Web服務(wù)的入口,比如http://192.168.0.1/test/services/sayHelloService?method=sayHelloTo&aname=everybody
if(req.getParameterNames().hasMoreElements())
{
//如果客戶端調(diào)用的方法正確,則Axis會調(diào)用相應(yīng)的JavaBean,并把JavaBean的返回結(jié)果
//封裝為Soap消息流返回給客戶端。
}
}
}
而Axis怎樣找到我們所請求的JavaBean呢?答案是server-config.wsdd文件。
server-config.wsdd
WSDD是web service deployment descriptor的縮寫。
最外面的
接著的
在這個例子中,我們指出service名字是sayHelloService ,provider是"java:RPC",它是axis 的標(biāo)記,指示這是一個java的RPC service,
而處理它的真正的class是org.apache.axis.providers.java.RPCProvider。
接著我們要在
"*"表示所有的公共方法,我們也列出方法名字列表,可以空格或逗號分割它們。