webservice原理及基于cxf开发的基本流程
一、SOA和webservice
SOA(service-Oriented Architecture)是面向服务的架构,是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以使用一种统一和通用的方式进行交互。web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。web service是实现SOA架构的一种技术,XML+XSD,SOAP和WSDL就是构成WebService平台的三大技术。
1、XML+XSD:
XML是WebService平台中表示数据的格式。 WebService采用HTTP协议传输数据,采用XML格式封装数据(即XML中说明调用远程服务对象的哪个方法,传递的参数是什么,以及服务对象的返回结果是什么)除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。
XSD(XML Schema)解决了数据数据类型的问题,例如,整形数到底代表什么?16位,32位,64位?它定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。WebService平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时,为了符合WebService标准,所有你使用的数据类型都必须被转换为XSD类型。
2、SOAP
SOAP即简单对象访问协议(Simple Object Access Protocol),它是用于交换XML。WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。SOAP提供了标准的RPC方法来调用Web Service。 SOAP协议 = HTTP协议 + XML数据格式。
3、WSDL
WSDL是Web Service描述语言,用于描述Web Service及其函数、参数和返回值。它是WebService客户端和服务器端都能理解的标准格式。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应WebService的代理类代码。WSDL文件保存在Web服务器上,通过一个url地址就可以访问到它。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。
二、调用webservice的本质
调用一次webservice的本质如下:
1、客户端把调用方法参数转换生成XML文档片段(SOAP消息),且该文档必须符合WSDL定义的格式;
2、通过http协议把XML文档片段传给服务器;
3、服务器接受到XML文档片段;
4、服务器解析XML文档片段,提取其中的数据;
5、服务器执行方法;
6、服务器把执行方法得到的返回值转换成符合WSDL定义的XML文档片段;
7、通过http协议把XML文档片段传输给客户端;
8、客户端接受XML文档片段;
9、客户端解析XML文档,提取其中的数据。
所以从本质上来看,要支持webservice,必须支持XML文档解析、生成以及支持网络传输。
三、基于CXF的webservice开发
(1)基本开发流程
1、服务器端
Ⅰ)开发web service业务接口,该接口用@WebService修饰;
Ⅱ)开发web service业务接口的实现类,也要用@WebService修饰;
Ⅲ)使用EndPoint类的静态方法publish()来发布web service。
2、客户端
Ⅰ)调用CXF提供的wsdl2java工具,根据WSDL文档生成相应的Java代码(任何语言实现web service都要暴露WSDL文档);
Ⅱ)找到wsdl2java所生成的类中一个继承了Service的类(该类的实例可当工厂使用);
Ⅲ)调用Service子类的实例的getXXXPort()方法,返回给远程web service的代理。
(2)使用CXF开发示例
1、下载CXF工具包apache-cxf-2.4.0,配置用户变量PATH,如D:\myeclipse\apache-cxf-2.4.0\bin;
2、服务器端:
创建一个Java project,工程名如:WS_Server
导入CXF工具包lib目录下的jar包
业务接口
package org.kfserver.ws; import javax.jws.WebService; @WebService public interface PlaceIntrod { public String getIntrod(String place); }
业务接口实现
package org.kfserver.ws.impl; import javax.jws.WebService; import org.kfserver.ws.PlaceIntrod; @WebService(endpointInterface="org.kfserver.ws.PlaceIntrod",serviceName="PlaceIntrodImpl") public class PlaceIntrodImpl implements PlaceIntrod { public String getIntrod(String place) { return "旅游"+place+",人间天堂。"; } }
发布服务
package kfs; import javax.xml.ws.Endpoint; import org.kfserver.ws.PlaceIntrod; import org.kfserver.ws.impl.PlaceIntrodImpl; public class ServerMain { public static void main(String[] args) { PlaceIntrod pi=new PlaceIntrodImpl(); Endpoint.publish("http://59.71.227.132/kfserver",pi); } }
2、客户端:
创建一个Java project,工程名如:WS_Client
根据WSDL文档生成相应的Java代码:cmd->你的工程目录\src>wsdl2java http://59.71.227.132/kfserver?wsdl
通过wsdl2java生成的Service的子类如下
package org.kfserver.ws.impl; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceFeature; import javax.xml.ws.Service; import org.kfserver.ws.PlaceIntrod; @WebServiceClient(name = "PlaceIntrodImpl", wsdlLocation = "http://59.71.227.132/kfserver?wsdl", targetNamespace = "http://impl.ws.kfserver.org/") public class PlaceIntrodImpl extends Service { public final static URL WSDL_LOCATION; public final static QName SERVICE = new QName("http://impl.ws.kfserver.org/", "PlaceIntrodImpl"); public final static QName PlaceIntrodImplPort = new QName("http://impl.ws.kfserver.org/", "PlaceIntrodImplPort"); static { URL url = null; try { url = new URL("http://59.71.227.132/kfserver?wsdl"); } catch (MalformedURLException e) { java.util.logging.Logger.getLogger(PlaceIntrodImpl.class.getName()) .log(java.util.logging.Level.INFO, "Can not initialize the default wsdl from {0}", "http://59.71.227.132/kfserver?wsdl"); } WSDL_LOCATION = url; } public PlaceIntrodImpl(URL wsdlLocation) { super(wsdlLocation, SERVICE); } public PlaceIntrodImpl(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public PlaceIntrodImpl() { super(WSDL_LOCATION, SERVICE); } /** * * @return * returns PlaceIntrod */ @WebEndpoint(name = "PlaceIntrodImplPort") public PlaceIntrod getPlaceIntrodImplPort() { return super.getPort(PlaceIntrodImplPort, PlaceIntrod.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. * @return * returns PlaceIntrod */ @WebEndpoint(name = "PlaceIntrodImplPort") public PlaceIntrod getPlaceIntrodImplPort(WebServiceFeature... features) { return super.getPort(PlaceIntrodImplPort, PlaceIntrod.class, features); } }
客户端调用服务(PlaceIntrod pi相当于服务器端的代理)
package kfc; import org.kfserver.ws.PlaceIntrod; import org.kfserver.ws.impl.PlaceIntrodImpl; public class ClientMain { public static void main(String[] args) { PlaceIntrodImpl pii=new PlaceIntrodImpl(); PlaceIntrod pi=pii.getPlaceIntrodImplPort(); System.out.println(pi.getIntrod("钟祥")); } }