1,什么是 Web 服务?
Web 是使应用程序可以以与平台和编程语言无关的方式进行相互通信的一项技术。Web 服务是一个软件接口,它描述了一组可以在网络上通过标准化的 XML 消息传递访问的操作。它使用基于 XML 语言的协议来描述要执行的操作或者要与另一个 Web 服务交换的数据。一组以这种方式交互的 Web 服务在面向服务的体系结构(Service-Oriented Architecture,SOA)中定义了特殊的 Web 服务应用程序。
2, 什么是SOAP?
SOAP (Simple Object Access Protocol )简单对象访问协议是在分散或分布式的环境中交换信息并执行远程过程调用的轻量级协议,是一个基于XML的协议。使用SOAP,不用考虑任何特定的传输协议(最常用的还是HTTP协议),可以允许任何类型的对象或代码,在任何平台上,以任何一种语言相互通信。
SOAP 包括四个部分: SOAP 封装 (envelop) ,封装定义了一个描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们的框架; SOAP 编码规则( encoding rules ),用于表示应用程序需要使用的数据类型的实例; SOAP RPC 表示 (RPC representation) ,表示远程过程调用和应答的协定; SOAP 绑定( binding ),使用底层协议交换信息。
应用中比较关注的是 envelop ,由一个或多个 Header 和一个 Body 组成。
SOAP 在可互操作的基础 Web 服务协议栈 中的位置 :
3, 什么是Axis?
Axis 本质上就是一个SOAP引擎 ( Apache Axis is an implementation of the SOAP ), 提供创建服务器端、客户端和网关SOAP操作的基本框架。但Axis并不完全是一个SOAP引擎,它还包括:
是一个独立的SOAP服务器。
是一个嵌入Servlet引擎(例如Tomcat)的服务器。
支持WSDL。
提供转化WSDL为Java类的工具。
提供例子程序。
提供TCP/IP数据包监视工具。
4, Axis 相比Soap v2的优点:
Axis 是第三代Apache SOAP的实现,从2000年起,SOAP v2开发小组开始讨论如何让Axis更加灵活、可配置,以及能够处理SOAP和来自W3C的各种XML标准。通过不断地讨论和代码编写,Axis目前相比SOAP V2取得了如下成果:
速度提高。 Axis通过基于事件的SAX对XML文档进行处理,从而在速度和效率上比Apache SOAP有所提高。
灵活性提高。
稳定性提高。
提供面向组件的部署。
提供一个简洁的传输抽象框架。其核心引擎完全于传输方式独立。从而使基于何种协议传输的选择更加灵活。
支持WSDL。包括WSDL和客户端代码生成等。
5, 什么是WSDL?
WSDL ( Web Service Description Language ) Web 服务器描述语言是用 XML 文档来描述 Web 服务的标准,是 Web 服务的接口定义语言,由 Ariba 、 Intel 、 IBM 、 MS 等共同提出,通过 WSDL ,可描述 Web 服务的三个基本属性:
·服务做些什么——服务所提供的操作(方法)
·如何访问服务——和服务交互的数据格式以及必要协议
·服务位于何处——协议相关的地址,如 URL
WSDL 文档以端口集合的形式来描述 Web 服务, WSDL 服务描述包含对一组操作和消息的一个抽象定义,绑定到这些操作和消息的一个具体协议,和这个绑定的一个网络端点规范。
WSDL 在Web 服务概念性协议栈 中的位置:
6, 什么是WSDD?
WSDD 就是 WEB 服务分布描述( Web Service Deployment Descriptor ) , 它定义了 WEB 服务的接口,如服务名、提供的方法、方法的参数等信息。
7, 什么是UDDI?
UDDI 就是统一描述、发现和集成( Universal Description, Discovery, and Integration )。 UDDI 用于集中存放和查找 WSDL 描述文件,起着目录服务器的作用。
Web 服务中的角色、操作和构件 :
- 服务提供者。从企业的角度看,这是服务的所有者。从体系结构的角度看,这是托管访问服务的平台。
- 服务请求者。从企业的角度看,这是要求满足特定功能的企业。从体系结构的角度看,这是寻找并调用服务,或启动与服务的交互的应用程序。服务请求者角色可以由浏览器来担当,由人或无用户界面的程序(例如,另外一个 Web 服务)来控制它。
- 服务注册中心。这是可搜索的服务描述注册中心,服务提供者在此发布他们的服务描述。在静态绑定开发或动态绑定执行期间,服务请求者查找服务并获得服务的绑定信息(在服务描述中)。对于静态绑定的服务请求者,服务注册中心是体系结构中的可选角色,因为服务提供者可以把描述直接发送给服务请求者。同样,服务请求者可以从服务注册中心以外的其它来源得到服务描述,例如本地文件、FTP 站点、Web 站点、广告和服务发现(Advertisement and Discovery of Services,ADS)或发现 Web 服务(Discovery of Web Services,DISCO)。
8, AXIS 的几种服务类型:
AXIS 有四种 service styles ,分别是: RPC, Document, Wrapped, 和 Message 。最常用的就是 RPC 和 Message 。
RPC : 在 AXIS 中是一个默认选项。当你部署的时候使用下列两种方式: 或则 ,它遵循 SOAP RPC 和编码规则。每个 RPC 都包括一个表示名称的外部接点和一些表示参数的内部接点。 AXIS 会根据规则将一个 XML ( WSDL 文件)文件转化成一个 JAVA 对象,并对对想赋上在文件中描述的值。也可以根据规则将一个 JAVA 对象转化成 XML 文件。
Document
适合于老的 XML schema 。
Wrapped
和 DOCUMENT 一样,适合于老的 XML schema 。
在大多书情况下,你不许要担心是 DOCUMENT 服务还是 WRAPPED 服务。
Message
以这种方式部署的话,会使 AXIS 失去意义,它使你的代码真正的用 XML 形式,而不需要转化成 JAVA 对象。以这种方式部署的有以下四种服务方法:
public Element [] method(Element [] bodies);
public SOAPBodyElement [] method (SOAPBodyElement [] bodies);
public Document method(Document body);
public void method(SOAPEnvelope req, SOAPEnvelope resp);
几种服务类型的主要区别:
基于 RPC( 远程过程调用 ) 方式,这也是 Web 服务最常用的方式。面向消息 / 文档的的类型跟 RPC 不同的是它提供了一个更底层的抽象,要求更多的编程工作。客户端可以传入任何的 XML 文档,得到的响应不一定是 SOAPEnvelope ,可以返回任何它所需要的东西,甚至不返回。虽然这对开发者来说非常的灵活,但是这种通讯类型在实际的应用中并不常见。面向消息 / 文档的 Web 服务主要适合于下面几种情况,比如批量处理,基于表单的数据导入,有需要返回非 XML 数据时, Web 服务器实现中要求直接访问传输层等等
二, 开发,部署Web服务:
首先下载并安装 tomcat4.x. 及以上版本
然后到 Axis 主页下载,现在最新版本是 1.3 final, 我们使用的是1.2.1 final版,将解压的axis中的webapps目录下的axis拷贝到tomcat安装路径下的webapp下,将解压的axis下lib下的jar文件拷贝到tomcat安装目录下commonlib下,并把他们加入到你的系统路径中。
然后启动 tomcat ,
打开 IE ,输入: http://localhost:8080/axis ,如果出现 axis 主页,说明安装 axis 成功。
部署 web 服务 在 axis 下部署 web 服务有以下两种方式:
1. 即时部署 (Instance Deployment) 利用 JWS 文件
只需要将 .java 文件拷贝到 axis 目录下,并将文件后缀改为 .jws 即可。
访问部署后的 wsdl 文件只需键入: http://localhost:8080/axis/filename.jws?wsdl
以下是 WSDL 的一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://service.kernel.gamebase.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://service.kernel.gamebase.com" xmlns:intf="http://service.kernel.gamebase.com" xmlns:tns1="http://vo.service.kernel.gamebase.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types> // 描述消息中复杂数据类型的使用
<schema targetNamespace="http://vo.service.kernel.gamebase.com" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://service.kernel.gamebase.com"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="UserGameGrade">// 定义复杂类型
<sequence>
<element name="MClassID" nillable="true" type="xsd:string"/>
<element name="gameID" nillable="true" type="xsd:string"/>
<element name="gradeType" type="xsd:int"/>
......
</sequence>
</complexType>
</schema>
......
</wsdl:types>
<wsdl:message name="getGameGradeRankResponse">// 定义操作的输出参数
<wsdl:part name="getGameGradeRankReturn" type="tns1:GameGradeRank"/>
</wsdl:message>
<wsdl:message name="getGameGradeRankRequest">// 定义操作的输入参数
<wsdl:part name="in0" type="xsd:string"/>
<wsdl:part name="in1" type="xsd:int"/>
<wsdl:part name="in2" type="xsd:int"/>
</wsdl:message>
......
<wsdl:portType name="GameGradeService"> // WSDL: portType 元素中定义了 Web 服务的操作。
<wsdl:operation name="getGameGradeRank" parameterOrder="in0 in1 in2"> // 操作定义了输入和输出数据流中可以出现的 XML 消息
<wsdl:input message="impl:getGameGradeRankRequest" name="getGameGradeRankRequest"/>
<wsdl:output message="impl:getGameGradeRankResponse" name="getGameGradeRankResponse"/>
</wsdl:operation>
<wsdl:operation name="getUserGameGradeRank" parameterOrder="in0 in1 in2 in3 in4">
<wsdl:input message="impl:getUserGameGradeRankRequest" name="getUserGameGradeRankRequest"/>
<wsdl:output message="impl:getUserGameGradeRankResponse" name="getUserGameGradeRankResponse"/>
</wsdl:operation>
......
</wsdl:portType>
<wsdl:binding name="GameGradeServiceSoapBinding" type="impl:GameGradeService">// 描述特定服务接口( WSDL: portType )的协议、数据格式、安全性和其它属性
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getGameGradeRank">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getGameGradeRankRequest">
<wsdlsoap:body namespace="http://service.kernel.gamebase.com" use="literal"/>
</wsdl:input>
<wsdl:output name="getGameGradeRankResponse">
<wsdlsoap:body namespace="http://service.kernel.gamebase.com" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="GameGradeServiceService">// 定义服务:名字, 访问点 ,位置
<wsdl:port binding="impl:GameGradeServiceSoapBinding" name="GameGradeService">
<wsdlsoap:address location="http://localhost:8080/gamebase/services/GameGradeService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions> 2 .定制部署 (Custom Deployment) 利用部署描述符 wsdd
以下是部署描述符的一个例子: <deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="GameGradeService" type="" provider="java:RPC"
style="rpc" use="encoded"> // 服务名字,服务类型及服务提供者
<parameter name="scope" value="Request"/>
<parameter name="className" value="/blog/com.gamebase.kernel.service.ServiceImpl"/>// 实现该服务的具体类
<parameter name="allowedMethods" value="*"/>
<namespace>http://service.kernel.gamebase.com</namespace>
<typeMapping xmlns:ns1="http://vo.service.kernel.gamebase.com" // 类型映射
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
qname="ns1:GameGradeRank"//Qualified Name (特定名字)
languageSpecificType="java:com.gamebase.kernel.service.vo.GameGradeRank"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"// 指定序列化工厂
deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory" // 反序列化工厂 name="GameGradeRank"/>
………
</service>
</deployment>
访问部署后的wsdl文件只需键入
http://localhost:8080/axis /services/ GameGradeService
三, 在IDE下开发Web服务:
1, 在Jubilder下开发WebService:
使用Jbuilder集成开发环境,能够根据服务接口类生成web服务描述文件,web服务部署描述文件及客户端代码,这样能够节省我们大部分时间(开发,配置),且减少出错机率。
Jbuilder 在以前的版本,如jbuilder8(可能更低版本)就支持Axis,我用的是Jbuilder2006,不过大体步骤都是相同。
在开始前,我们有个服务接口GameGradeService类,服务接口实现类ServiceImpl类及相关附属类。我们要实现该服务接口。
2.1 ,打开Jbuilder,新建一个工程,如testWebService
2.2 ,新建一个名为webService的WebService Server (file>new:WebServices:Axis WebServices Server Configuration)
2.3, 在出现的Web Services Designers可视化界面,点击“create Service”,选择“java Service”
2.4 ,配置新创建的java Service,点击JavaService1,配置Service Name为GameGradeService,服务接口为我们有的那个服务接口GameGradeService,实现类为我们实现改接口的类ServiceImpl。
2.5 ,然后编译该工程,能够生成web服务部署文件,web服务描述文件,如果你选择了生成客户端代码的话,它也能生成相应的客户端代码。
2.6 ,启动该服务,访问 :http://localhost:8080/webService/services/GameGradeService?wsdl ,如果出现该服务的描述文档,说明发布成功。
2.7 ,执行自动生成的客户端代码进行测试,发现测试成功。
2.8 ,你可以用webService的webServices Client来根据wsdl只生成客户端代码。
a, 新建一个名为webServiceClient的WebService Client(file>new:WebServices:Axis WebServices Client Configuration)
b, 在出现的Web Services Designers可视化界面,点击“create Service”,选择“import from url”
c, 配置新创建的java Service,点击JavaService1,配置Service Name为GameGradeService,Input WSDL file 为给定的wsdl。
d, 然后编译该工程
2, 在eclipse下开发WebService:
Eclipse3.1 及相关插件已经能够很好的支持webService开发。
右键点击wsdl文件,选择webServices,有以下功能:发布wsdl文件,生成客户端代码等。
右键 点击服务接口文件,选择webServices,有以下功能:生成web Service等。
同时eclipse提供了友好的界面操作,如测试的时候,提供界面让你输入参数,而不必该改程序。
四, 开发过程中的问题:
在使用 AXIS 开发WEB服务的时候,会遇到很多问题。比如:XML解析器出现的异常、客户端程序找不到可用的Web服务、序列化/反序列化等。
XML 解析器出现的异常主要是由于类型映射的问题导致的,用到那个Bean就把那个bean映射进去就可以避免该问题。
客户端程序找不到可用的Web服务主要是由于客户端对服务提供者的url及服务名字输入有错,这一般是由于手写客户端代码造成的。
序列化/反序列化问题,没有对传输中的某个Bean类型映射相应的序列化/反序列化工厂,或者是复杂类型中,没有实现自定义的序列化/反序列化工厂。
以上是开发过程中主要遇到的几类问题,在以后的开发过程中,一定还会需要遇到更多的问题。
五, 其他相关知识:
1 ,java类与wsdl相互生成工具:
Axis 提供了”WSDL2Java”工具,可以利用wsdl描述来产生服务的Java代理和框架(proxy and skeletons)。
Axis 提供了”Java2WSDL”工具,可以由java类生成wsdl文件。
2, 序列化与反序列化:
序列化/反序列化器在英文中的对应翻译是Serializer/Deserializer,一个序列化器的功能是遵循一定的映射规则和编码风格,将一种类型的JAVA对象通过某种特定的机制,转换成为XML描述的形式;反序列化器的功能是序列化器所做工作的逆操作,两者相辅相成,成对出现。Axis中的序列化/反序列化器采用设计范式中的工厂模式,每一个Serializer唯一对应一个SerializerFactory;每一个Deserializer唯一对应一个DeserializerFactory。
Axis 已经为开发者提供了丰富的序列化/反序列化器,对于java的基本数据类型,绝大部分常用的容器类(比如数组类型,Vector类型等)都提供了实现,特别是提供了对W3C的DOM对象(比如Document, Element等)和符合Bean规范的JAVA对象提供了功能完善的序列化/反序列化器,但对于一些特殊类型的对象,需要通过Web服务进行传递,我们不得不开发自己的序列化/反序列化器。
3 ,Axis与Spring的结合:
Axis 与spring结合,需要提供一些额外工作,即将实现web服务接口的Bean与web服务部署中服务类如何关联。 如下:
<service name="GameService" type="" provider="Handler" style="rpc">
<parameter name="handlerClass" value="/blog/com.workingmouse.webservice.axis.SpringBeanRPCProvider"/>
<parameter name="springBean" value="gameInfoService"/>
<parameter name="springBeanClass" value="/blog/com.gamebase.kernel.service.GameService"/>
<parameter name="scope" value="Request"/>
<parameter name="allowedMethods" value="*"/>
.......
</service>
参数handlerClass的值是处理Bean与wsdd文件中服务类的关联。
参数springBean的值表示实现接口GameService注册的Bean的名字。
参数springBeanClass的值表示接口GameService的类。