下面根据配置文件,来说明一些底层与web services的关系:
回顾一下servlet的映射模式。我们知道,servlet是从javax.servlet.http.httpservlet继承的,在服务器端被载入jvm执行,然后向客户端输出html流。
servlet的web.xml文件(位于 webapps/foo/web-inf目录):
<?xml version="1.0" encoding="utf-8"?>
<!doctype web-app public "-//sun microsystems, inc.//dtd web application 2.2//en"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
</web-app>
invoker servlet 其实是:org.apache.catalina.servlets.invokerservlet
按类名提供小服务程序。例如,如果您调用 foo/servlet/helloservlet,
invoker servlet将装入该helloservlet(如果它在其类路径中的话)并执行。
初看上面的web.xml,好像只给出了一个servlet映射,而没有定义invoker servlet。
其实,invoker servlet 是在tomcat的conf目录中的web.xml中定义的::
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.invokerservlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
所以,如果抛开tomcat_home/conf/web.xml,我们这样定义一个web.xml,似乎更能清楚的说明问题:
<?xml version="1.0" encoding="utf-8"?>
<!doctype web-app public "-//sun microsystems, inc.//dtd web application 2.2//en"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<servlet-name>myinvoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.invokerservlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myinvoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
</web-app>
即所有/servlet/* 模式的url,都会交给org.apache.catalina.servlets.invokerservlet来处理。
或者说,所有/servlet/* 模式的url,其实都是调用invokerservlet这个类,而invokerservlet本身也是
一个servlet,它也是从 httpservlet 继承而来的。
这样,我们自己的servlet就能够通过特定的url执行,即 /servlet/ourservlet。
当然,如果你高兴,可以定义任何的 url pattern,而不一定是 /servlet/*,这一点,正如我们后面
看到的axis处理soap消息的方法。
进一步,如果不想让 invokerservlet 在中间“捣鬼”,我们当然可以直接定义自己的servlet:
<?xml version="1.0" encoding="utf-8"?>
<!doctype web-app public "-//sun microsystems, inc.//dtd web application 2.2//en"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<servlet-name>myinvoker2</servlet-name>
<servlet-class>
com.foo.myservlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myinvoker2</servlet-name>
<url-pattern>/anyname/*</url-pattern>
</servlet-mapping>
</web-app>
jsp也是一样的道理,有了上面的分析,
看看tomcat_home/conf/web.xml中的如下语句就可以jsp的处理方法了,这里就不再废话了:
....
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.jspservlet</servlet-class>
<init-param>
<param-name>logverbositylevel</param-name>
<param-value>warning</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
....
进入正题。
我们先来看部署web service的web.xml:
<?xml version="1.0" encoding="iso-8859-1"?>
<!doctype web-app public "-//sun microsystems, inc.//dtd web application 2.2//en" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<servlet>
<servlet-name>axis</servlet-name>
<!--实际servlet程序,这里是axisservlet-->
<servlet-class>org.apache.axis.transport.http.axisservlet</servlet-class>
</servlet>
<!-- ### 定义servlet和url的对应关系-->
<servlet-mapping>
<servlet-name>axis</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
</web-app>
所有 /services/* 模式的 url 都会交给org.apache.axis.transport.http.axisservlet处理,
axisservlet当然也是从httpservlet继承而来的。这就是为什么我们部署的web服务在调用时都要在
服务名称前加上 services/ 了。
可以说,axisservlet是所有web服务调用的入口。
那么axisservlet在接手web服务调用后都做了哪些工作呢?
客户端用call.invoke()调用web服务用的是post,所以入口是axisservlet.dopost...
而不是axisservlet.doget...
先来看看axisservlet的dopost函数,这里只给出了关键语句及注释:
/**
* 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); //调用客户端请求的服务
responsemsg = msgcontext.getresponsemessage();//得到调用的返回结果
sendresponse(getprotocolversion(req), contenttype, res, responsemsg);//将结果送至客户端
}
这样一来,web服务调用的来龙去脉就大致清楚了。。。
为了高清楚前面我们的三个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
是怎样获得输出结果的,再来看看axisservlet的doget函数,这里只给出了流程框架及注释:
**
* 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文件中读取所有部署的服务信息,向向客户端列出所有部署的服务,
//包括每个服务可调用的方法。
}else
//如果路径不为空,比如:http://localhost/wstk/services/sayhelloservice
if(realpath != null)
{
//如果请求wsdl,比如:http://localhost/wstk/services/sayhelloservice?wsdl
if(wsdlrequested)
{
//创建sayhelloservice的wsdl文件并传送至客户端
} else
//这里是利用url调用web服务的入口,比如http://192.168.0.1/test/services/sayhelloservice?method=sayhelloto&aname=everybody
if(req.getparameternames().hasmoreelements())
{
//如果客户端调用的方法正确,则axis会调用相应的javabean,并把javabean的返回结果
//封装为soap消息流返回给客户端。
}
}
}
而axis怎样找到我们所请求的javabean呢?答案是server-config.wsdd文件。
server-config.wsdd
<?xml version="1.0" encoding="utf-8"?>
<deployment xmlns:java="http://xml.apache.org/axis/wsdd/providers/java" xmlns="http://xml.apache.org/axis/wsdd/">
<service name="sayhelloservice" provider="java:rpc">
<parameter name="classname" value="sayhello"/>
<parameter name="allowedmethods" value="sayhelloto"/>
</service>
<handler type="java:org.apache.axis.handlers.http.urlmapper" name="urlmapper"/>
<transport name="http">
<requestflow>
<handler type="urlmapper"/>
</requestflow>
</transport>
</deployment>
wsdd是web service deployment descriptor的缩写。
最外面的<deployment>元素指示这是wsdd,并定义了java的名字空间。
接着的 <service>元素定义了service。一个service是一个目标链,包括请求request、内容提供者provider、响应response。
在这个例子中,我们指出service名字是sayhelloservice ,provider是"java:rpc",它是axis 的标记,指示这是一个java的rpc service,
而处理它的真正的class是org.apache.axis.providers.java.rpcprovider。
接着我们要在<parameter>中告诉rpcprovider,它如何实例化并调用正确的class(如:com.foo.myservice)。
<parameter>元素的classname指示class名,allowedmethods告诉引擎那些共用的方法要通过soap来调用。
"*"表示所有的公共方法,我们也列出方法名字列表,可以空格或逗号分割它们。
文章整理:西部数码 、
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!