1 Web Service 简介
1.1 什么是Web Service?
从表面上看,Web service 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web service 的应用程序叫做客户。
另一种更精确的解释:Web services是建立可互操作的分布式应用程序的新平台。Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service,只要我们可以通过Web service标准对这些服务进行查询和访问。Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。在传统的分布式系统中,基于界面(interface)的平台提供了一些方法来描述界面、方法和参数(译注:如COM和COBAR中的IDL语言)。同样的,Web service平台也必须提供一种标准来描述Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。
1.2 Web Service用到的技术
为了实现平台无关,实现独立的访问Web服务, 业界制定了一系列技术标准,下面是一些重要的技术:
1. XML
可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。它的内容与表示的分离十分理想,除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。无关性是比技术优越性更重要的:软件厂商是不会选择一个由竞争对手所发明的技术的。
2. SOAP
Web service建好以后,你或者其他人就会去调用它,简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service,SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP,SOAP也是基于XML,XML是SOAP的数据编码方式。
3. WSDL
你会怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码。
2 用XFire进行Web Service开发
2.1 XFire简介
在架构上可以把XFire大概分为 Service, Transport 和 Invoker 三个层面。
Service 层是 XFire 架构的静态基础,负责完成对服务的注册及其管理。核心的 ServiceRegistry 接口完成对服务自身的生命期管理,如注册/注销/获取等等;而 ServiceFactory 接口则负责从具体的 POJO 类型,生成实现 Service接口的可被管理的服务代理。
Transport 层则是 XFire 的外部 IO 处理系统。由 TransportManager 接口对具体的 Transport 接口实现进行管理,默认提供了基于 pipe 的 LocalTransport 和基于 Http 协议的 SoapHttpTransport。理论上可以任意进行扩展,例如 XFire 发布包中还提供了基于 JMS 和 XMPP 的实现。
Invoker 则是 XFire 的动态调用层,负责在 Transport 层接受到请求后,解析内容、调用合适服务并最终返回 SOAP 封包给调用者。运行时 Invoker 负责维系 Service 和 Transport 之间的联系。
因此一个服务的生成和注册往往类似如下代码:
[code]Service endpoint = serviceFactory.create(clazz);// 根据具体类型创建服务
XFire.getServiceRegistry().register(endpoint);// 向服务管理注册服务
endpoint.setInvoker(new BeanInvoker(bean));// 设定服务调用模式
[/code]
最基本的XFire 接口,实际上就是 getServiceRegistry()和getTransportManager() 的封装。
XFire 中另一块核心的思想,就是其灵活而强大的 binding 机制,负责完成 Java 类型与 SOAP 消息的双向转换。XFire仅仅内建就支持 POJO(Aegis), Castor,JAXB 1.1, JAXB 2.0 和 XMLBeans 多种模式,你可以根据需求选择从全自动POJO生成,到全手工 xsd 文件定义的不同方式。
2.2 配置XFire
XFire的官方下载地址: http://XFire.codehaus.org/
从官方网站下载到本地机器后解压,目录结构如下:
XFire-distribution-1.1-beta-1
|____api (javadoc文档)
|____examples (XFire例子)
|____lib (XFire所需的jars包)
|____modules (XFire模块)
|____XFire-all-1.1-beta-1.jar
|____几个授权和说明TXT文档
XFire的配置我们以一个简单的Web服务的例子来进行说明,并且在这里你将了解到如何将一个java文件转换成web服务?services.xml文件是如何定义的?如何发布这个web服务?如何获得这个服务的WSDL?
首先打开Eclipse,创建一个工程。目录结构如下图:
创建一个简单的java文件,这个java文件只提供一个MathService方法(文件所在位置:Src/com/mybank/XFire/example/MathService.java)。
在WebRoot/WEB-INF/classes目录下创建META-INF/XFire目录,然后在META-INF/XFire目录下创建services.xml文件,文件内容为:
这个文档定义了你要发布的Web服务,定义了一个名为MathService的服务,服务类为
com.mybank.XFire.example.MathService。具体解释如下:
对Web服务的定义包含在<service>元素内,<service>元素下还有若干子元素。
第一个子元素是<name>,你可以提供任何有效的xml名字,这个名字会被客户端程序和服务器上的其他组件使用。例如,当服务器起来以后,你可以在浏览器上使用这个名称来查看WSDL。
下一个子元素是<namespace>,任何有效地xml名称都可以,<namespace>将作为你服务器的唯一标识变量使用。
<serviceClass>元素包含Java类名用来指明方法的签名。
<implementationClass>
元素记录实现接口的Java类名。
这是一个可选元素,如果前一个元素
<serviceClass>填入的是接口
,
那么此处就要填入相应的实现类名。
注:你可以在services.xml文件中定义多个Web服务。
Web应用的部署描述:
将需要的库文件copy到工程的lib目录下,所需的库文件如下:(这些jar文件可以从distribution和它的lib目录下得到)
- activation- 1.0.2 .jar
- commons-codec-1.3.jar
- commons-httpclient-3.0.jar
- commons-logging- 1.0.4 .jar
- jaxen-1.1-beta-8.jar
- jdom-1.0.jar
- log4j-1.2.x.jar
- mail- 1.3.3 _01.jar
- spring-1.2.x.jar
- stax-api-1.0.jar
- wsdl4j- 1.5.2 .jar
- wstx-asl-2.9.jar
- xbean- 2.1.0 .jar
- xbean-spring-2.2.jar
- XFire-all-1.0.jar
- XmlSchema-1.0.jar
这样我们一个简单的web服务就开发完了,下面就要将它发布出去。
利用Eclipse进行部署(具体怎样部署略),启动tomcat,你就可以检查这个web服务是否发布成功。
打开浏览器,在浏览器地址栏中输入http://localhost:8080/XFireProject/services/MathService?wsdl
可以查看这个web服务的wsdl文档。
如果在你的机器上显示如上图所示,那么说明你的这个web服务发布成功,可以正常提供基于http的web服务。
2.3 使用XFire开发Web服务的基本步骤
1、检验Java类的方法和构造函数是公共的(public)。
2、将XFire Servlet相关的入口添加到web.xml中。
3、创建services.xml并把它放到WEB-INF/classes/META-INF/XFire目录下。
4、将XFire和其他第三方库添加到你的Web应用的WEB-INF/lib 目录下。
2.4 集成Spring
XFire可以很好的集成到Spring中去,Spring已经做了这方面的集成!
首先,我们先来创建我们的工程,目录结构如图:
然后,创建web服务,采用接口和实现类的方式。
接口EchoHello.java
实现类EchoHelloImpl.java
作为web服务的java文件我们已经建好了,下面要做的事情就是配置了。
在WEB-INF文件夹下创建applicationContext.xml文件,这是Spring的配置文件,如果你使用其它的Spring配置文件,可以将下面的bean添加到那个配置文件中去。
这里定义了echoBean,这个Bean就是我们的实现类,当然你也可以在这里定义其它需要Spring管理的Bean。
META-INF/XFire/services.xml文件可以省略了,因为web服务的定义在XFire-servlet.xml中可以找到。
在WEB-INF文件夹下创建XFire-servlet.xml文件,根据Spring规范这个文件名起做XFire-servlet.xml,其中XFire是web.xml配置的DispatcherServlet名称:
这个文件的上半部分将EchoHelloService这个URL和math这个bean联系在一起。下半部分定义了Web服务的bean和服务接口。其中echoBean是我们在applicationContext.xml中配置的那个bean。
最后一步就是修改web.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app>
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml classpath:org/codehaus/xfire/spring/xfire.xml </param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<servlet> <servlet-name>xfire</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>xfire</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
</web-app> |
org/codehaus/XFire/spring/XFire.xml
文件为TransportManager, ServiceRegistry 和一些简单的 ServiceFactorys包含了一些标准的bean定义。
部署略。
这样,你就可以访问http://localhost:8080/XFireSpring/EchoHelloService来调用我们的web服务,也可以通过网址http://localhost:8080/XFireSpring/EchoHelloService?wsdl来查看wsdl文档。
至此我们web服务的开发、发布已经完成。
2.5 开发一个客户端来调用我们的web服务
说明:
这里所讲的客户端开发是手动的、很普遍的一种开发方式,由于其他一些因素的限制,象“利用WSDL产生客户端”等一些开发客户端的方法以后再逐渐深入研究。
首先,我们封装一下XFire service--proxy api,程序如下:
分析一下程序:首先我们创建了一个服务模型,里面包含了对服务的描述,换句话说,我们创建了服务的元数据。我们是用XFire的ObjectServiceFactory通过接口clazz创建了这个服务模型。
下一步就是获取XFire的代理对象,这一步中没有任何应用细节。通过proxyFactory,使用服务模型和服务终点URL(用于获得WSDL),我们获得了服务的本地代理。这个代理就是实际的客户端。
现在,可以调用我们的web服务了。
当web服务部署成功并启动的话,我们运行我们的客户端程序,将显示:
2.6 内含的XFire HTTP Service
n 开发步骤:
l 创建服务
l 用XFire's的内含的服务器来部署服务
l 为服务创建一个客户端
n 开发实例:
l 工程结构如下:
l 创建服务:
首要的任务是创建我们的服务,它是一个接口(interface),Java代理服务器(Proxies)需要这个接口。
也需要它的一个实现。
l 用XFire's的内含的服务器来部署服务
下面我们将要写一个叫做ServiceStarter的类,这个类从ServiceFactory创建一个服务,并且启动一个XFireHttpServer实例。
在XFire中ServiceFactorys负责创建和配置服务
l 为服务创建一个客户端
此处客户端的开发和集成Spring客户端的开发大致都是一样的,只需将
SERVICES_URL = http://localhost:8080/XFireSpring/EchoHelloService替换成
SERVICES_URL = http://localhost:8191/EchoHello(8191是端口号,可指定任意有效的端口号,这里为了和tomcat的8080端口进行区分)
启动服务端的服务(运行ServiceStarter中的start方法即可),就可以通过http://localhost:8191/EchoHello来调用我们的服务了。
2.7 关于WebService安全性的考虑
目前考虑实现的方式:
1. 基于Web容器的角色认证(正在研究中)。
2. 在应用程序中进行控制(目前可以实现)。
3. WS-Security(需要JDK1.5等)。
4. SOAP authentication with handlers(目前可以实现)。
下面主要介绍下SOAP authentication with handlers。一种是集成Spring的验证,另一种不是和Spring集成的,也就是一个普通的java Web服务。Web服务的开发这里不再详细介绍,仿照前面的例子即可,主要介绍一下和安全验证方面有关的。
u 集成Spring的Web服务安全验证
l 服务端(web服务的提供者)
1. 定义服务端的Handler,用来读取客户端传过来的Soap header
2. applicationContent.xml如下:
3. xfire-services.xml如下:
4. web.xml不用做修改
l 客户端(web服务的调用者)
1. 定义输出 Handler用于客户端创建Soap Header
2. 在客户端往输出Handler中加入验证Handler
u 普通的java服务
u 服务端(web服务的提供者)
1. 定义服务端的Handler,用来读取客户端传过来的Soap header
2. webservices.xml如下:
3. web.xml如下:
l 客户端(web服务的调用者)
与集成Spring的客户端是一样,这里略!!!
2.8 补充说明
u 对services.xml的补充说明:
1. 如果配置web服务的文件名字是默认的(即services.xml),那么web.xml文件不需要为Xfire配置相关信息去查找services.xml文件。web.xml文件如下:
services.xml文件放在这个路径下:
WEB-INF/META-INF/xfire/services.xml。
2. 如果配置web服务的文件名字不是默认的(即xxxx.xml),那么web.xml文件就需要为Xfire配置相关信息去查找services.xml文件。web.xml文件如下:
webservices.xml文件放在这个路径下:
WEB-INF/xfire/ webservices.xml(必须放在WEB-INF目录下)。