java

位置:IT落伍者 >> java >> 浏览文章

Java远程通信技术——Axis实战


发布日期:2019年06月20日
 
Java远程通信技术——Axis实战
前言

在 Internet 网络覆盖全球的今天网络通信已经是当今软件开发过程中离不开的话题在常用的WindowsLiunxUnix 系统当中大部分的网络数据传输都是使用 TCP/IPUDP/IP 作为底层传输协议的而 HTTP 协议就是基于 TCP/IP 协议而运行的超文本传送协议

在 JAVA 高级开发语言中陆续出现 RMICORBAJAXRPCJAXWSAxisXFireHTTP InvokerHessianBurlapJMX 等远程通信架构去实现系统之间数据传送远程通信技术 的一系列文章中本人将对上述复杂的 JAVA 远程通信技术作出归纳

首先在本篇文章中先对有着多年历史的 Axis 进行介绍

Axis 简介

Web 服务的起源

Web 服务是现今实现网络服务概念的趋势它把基础架构建立于标准化的XML语言之上能够使用一种与平台无关的方式对数据进行编码其中 SOAP 与 WSDL 都遵从此标准化的 XML 编码规则

SOAP (Simple Object Access Protocol简单对象访问协议)是一种轻量的简单的基于 XML 的协议用于描述在服务过程中服务器端与客户端之间所交换的消息 SOAP 可以和现存的许多因特网协议和格式结合使用包括超文本传输协议( HTTP)简单邮件传输协议(SMTP)多用途网际邮件扩充协议(MIME)

WSDL (Web Service Definition LanguageWeb服务描述语言)是一种基于 XML的协议用于定义服务端与客户端之间的契约描述Web服务的公共接口列出 Web服务进行交互时需要绑定的协议和信息格式

Web 服务采用 WSDL 语言描述该服务支持的操作和信息运行时再将实际的数据以 SOAP 方式在服务端与客户端进行信息传递

由于软件开发平台众多当中存在不同的开发风格当服务器端与客户端使用不同的开发工具时数据转换成为复杂且关键的问题而 SOAP 与 WSDL 的主要特性之一在于它们都是可扩展的且与开发平台无关为了建立统一的 XML 协议 微软IBMSunOracleBEA 等多家软件开发商联合起来组成了一个名为WSI(Web Service Interoperability)组织由该组织制定 WSReliableMessageWSDiscoveryWSFederationWSCoordinationWSAtomicTransactionWSBusinessActivity WSEnumerationWSEventing WSManagement 等一系列用于数据交换的规范

JAXRPC JAXWS 简介

JAXRPC ( Java API for XMLbased RPC ) 是 Java 库中基于 XML 远程服务的一组标准 API它通过 WSDL 方式对所提供的服务进行描述并以 RPC 的风格把 SOAP 信息进行公开是 Java 库中最早对 Web 服务提供支持的一组API

JAXRPC 从其名称可以看出最初的目的只是为了支持使用(Remote Procedure CallRPC) 的 XML 远程过程调用操作它以 BP (WSIs Basic Profile )为基础依赖于SAAJ (SOAP with Attachments API for Java)为规范虽然支持 SOAP 协议但对 Web 服务功能有一定的局限性于是在 年底开发团队对 JAXRPC 进行大幅修订由 Sun 公司组织了一个专家组开始进行 JAXRPC 规范的开发

JAXRPC 是基于 JAVA 而开发的它依赖于 Annotation 等新特性在JAXRPC 的基础上提供还增加了如异步回调面向消息等新增技术JAXRPC 以 BP (WSIs Basic Profile ) 为基础依赖于SAAJ (SOAP with Attachments API for Java)为规范能使用 SOAP SOAP 进行信息公开它是 JAXRPC 架构发展的成果在开发完成后JAXRPC 被正式改名成为 JAXWS ( Java API for XMLWeb Services )

Axis 概述

Axis 全称 Apache EXtensible Interaction System ( 阿帕奇可扩展交互系统 ) 它是一个 SOAP 引擎提供创建 Web 服务的基本框架Axis x 是基于 JAXRPC 而实现一个工具包它可以使用 HTTPJMSSMTP 等多种传输方式支持 SOAP

Axis x 是新一代的 Axis 引擎它支持 JAXWSJAXPRC 等 API并且在Axis x 的基础上增加了灵活数据绑定异步调用等新增功能可使用 SOAP SOAP 协议在服务请求上Axis x 支持三种请求响应模式InOnlyRobustIn和InOut也可支持使用 REST 风格的开发方式

基本的 Axis Web 服务由四部分组成Axis Servlet Axis 部署描述 远程服务接口服务实现类

Axis Servlet 是 Axis 的核心它负责 WSDL 基础服务信息的公开并把 SOAP 请求转化为 Java 方法的调用最后把返回值转化为 SOAP Axis Servlet 隐藏了构建 Web 服务的大量代码使用开发人员不用直接与 SOAP 打交道便可轻松完成 Web 服务的开发

Axis 部署描述是一个XML文档它用于管理 Web 服务的发布决定哪些服务类需要通过 SOAP 对外公开

远程服务接口并非必要的但在很多的 Web 服务开发过程中都会使用远程服务接口用于对外暴露服务类的方法在服务器端通过服务实现类去继承实现服务接口

由于 Axis x 与 Axis x 有各自的特色下面将分开来介绍

回到目录

Axis x 实例

Axis x 的下载与安装

Axis x 可于官网  下载完成下载后建立 Web Project 作为测试项目 把 lib 文件夹下的 jar 文件拷贝引入到测试项目当中

在 webxml 文件下加入 AxisServlet 配置后系统就会对以后缀为 *jws 及路径为 /services/* 的请求进行监听遇到此类请求时将把信息交由 orgapacheaxistransporthttpAxisServlet 进行处理

<webapp>

<displayname>ApacheAxisdisplayname>

<listener>

<listenerclass>orgapacheaxistransporthttpAxisHTTPSessionListenerlistenerclass>

listener>

<servlet>

<displayname>ApacheAxis Servletdisplayname>

<servletname>AxisServletservletname>

<servletclass>

orgapacheaxistransporthttpAxisServlet

servletclass>

servlet>

<servlet>

<displayname>Axis Admin Servletdisplayname>

<servletname>AdminServletservletname>

<servletclass>

orgapacheaxistransporthttpAdminServlet

servletclass>

<loadonstartup>loadonstartup>

servlet>

<servlet>

<displayname>SOAPMonitorServicedisplayname>

<servletname>SOAPMonitorServiceservletname>

<servletclass>

orgapacheaxismonitorSOAPMonitorService

servletclass>

<initparam>

<paramname>SOAPMonitorPortparamname>

<paramvalue>paramvalue>

initparam>

<loadonstartup>loadonstartup>

servlet>

<servletmapping>

<servletname>AxisServletservletname>

<urlpattern>/servlet/AxisServleturlpattern>

servletmapping>

<servletmapping>

<servletname>AxisServletservletname>

<urlpattern>*jwsurlpattern>

servletmapping>

<servletmapping>

<servletname>AxisServletservletname>

<urlpattern>/services/*urlpattern>

servletmapping>

<servletmapping>

<servletname>SOAPMonitorServiceservletname>

<urlpattern>/SOAPMonitorurlpattern>

servletmapping>

webapp>

而 SOAPMonitorService 并非必要配置但加入SOAPMonitorService 配置可以便于对服务运行时所传输的SOAP信息进行监听在服务的requestFlow或responseFlow 中加入 SOAPMonitorHandler 系统就可显示服务请求和回发时的 SOAP 信息

<deployment xmlns=

xmlns:java=>

<handler name=soapmonitor type=java:orgapacheaxishandlersSOAPMonitorHandler>

<parameter name=wsdlURL value=/axis/SOAPMonitorServiceimplwsdl/>

<parameter name=namespace

value=implwsdl/>

<parameter name=serviceName value=SOAPMonitorService/>

<parameter name=portName value=Demo/>

handler>

<service name=SOAPMonitorService provider=java:RPC>

<parameter name=allowedMethods value=publishMessage/>

<parameter name=className value=orgapacheaxismonitorSOAPMonitorService/>

<parameter name=scope value=Application/>

service>

<service name=myService provider=java:RPC>

<requestFlow>

<handler type=soapmonitor/>

requestFlow>

<responseFlow>

<handler type=soapmonitor/>

responseFlow>

<parameter name=allowedMethods value=*/>

<parameter name=className value=axisservermyService/>

service> deployment>

调用服务的三种方式

下面从最简单的 HelloWorld 开始介绍 Axis 的使用方法首先在 WEBINF 文件夹下建立 serverconfigwsdd 文件在 Axis x 当中此文件正是用于管理服务发布的默认配置文件首先 service 用于定义对外暴露的服务其中 name 属性用于定义服务的名称像下面例子当 name 为 PersonService 时对外暴露的服务路径则对应为  

而 parameter 用于定义服务的相关属性className 表示此服务的实现类而 allowedMethods 表示所公开的服务方法* 则默认为公开此类中的所有 public 公共方法而 scope 则是用于定义服务对象生成的方式它包括三个选项requestsessionapplication

request 是默认选择表示为每个请求生成一个服务对象

session 表示对同一个客户代理对象所发送的请求使用同一个服务对象并把服务信息放在同一个上下文当中当使用有状态服务时使用此 session 更为合适在下节将再作进一步介绍

application 类似于使用单体模式表示所示的请求均使用同一个服务对象当使用无状态服务时使用 application 能有效提高运行效率

最后在 transport 中定义一个 requestFlow 处理类 orgapacheaxishandlershttpURLMapper表示在系统接受到 http 请求时将会调用 URLMapper 类来处理路径映射等问题

<deployment xmlns=

xmlns:java=>

<service name=PersonService provider=java:RPC>

<parameter name=className value=axisserviceImplsPersonServiceImpl />

<parameter name=allowedMethods value=* />

<parameter name=scope value=application />

service>

<transport name=http>

<requestFlow>

<handler type=java:orgapacheaxishandlershttpURLMapper/>

requestFlow>

transport> deployment>

PersonService 服务代码如下此时运行服务输入路径  浏览器上将显示此服务的 wsdl 信息

public interface IPersonService {

String HelloWorld(String name) }

public class PersonServiceImpl implements IPersonService {

@Override

public String HelloWorld(string name){

return Hello +name;

} }

客户端的生成工具有多种其中一种是使用 Axis x 中的自带生成器 WSDLJava 此生成器可以根据 wsdl 文件生成客户端

首先在环境变量中把 Axis_Home 绑定到 Axis x 的根目录在 path 加入设置 ;%Axis_Home%\lib 然后输入

Java orgapacheaxiswsdlWSDLJava  p axisclientperson

此时系统将在 axisclientperson 包内生成客户端代码类 PersonServiceImplPersonServiceImplServicePersonServiceImplServiceLocatorPersonServiceSoapBindingStub

PersonServiceImplServiceLocator 用于实现 PersonServiceImplService 接口它绑定了服务的名称地址端口等详细资料

PersonServiceImpl 用于定义服务的接口而 PersonServiceSoapBindingStub 则是此服务代理它通过 SOAP 协议把操作请求发送到服务器并把返回信息转化为 Java 对象

public static void main(String[] args) throws

RemoteException MalformedURLException ServiceException {

// TODO Autogenerated method stub

HelloWorld()

}

private static void HelloWorld() throws

RemoteException MalformedURLException{

PersonServiceImpl personService=new PersonServiceSoapBindingStub(

new URL(

new PersonServiceImplServiceLocator())

Systemoutprintln(personServicehelloWorld(Leslie))

}

通过系统自动生成的代理类就能简单地调用远程服务这是因为在代理类中已经完成了大量关于PersonService 服务的配置但本人觉得想要深入地了解 Axis 的开发就应该了解其内部的结构所以在下面例子当中将介绍如何使用Axis的内部机制直接调用Web服务

在 orgapacheaxisclient 中存在着服务的基础类 Service 通过 Service 可用于管理服务的绑定地址端点获取服务的 WSDL 等详细信息另外 Call 类用于管理每个服务请求动作它可以设置每个请求的方法最后通过callinvoke(Object[])调用服务并获取完成后的返回值

public static void main(String[] args) throws

RemoteException MalformedURLException ServiceException {

HelloWorld()

}

private static void HelloWorld() throws

ServiceExceptionRemoteException{

//生成服务对象Service

Service service=new Service()

Call call=(Call) servicecreateCall()

//设置Endpoint地址

callsetTargetEndpointAddress(

//绑定请求方法名称

callsetOperationName(HelloWorld

//通过callinvoke调用服务获取返回值

String data=(String)callinvoke(new Object[]{Leslie})

Systemoutprintln(data)

}

如果觉得使用 Call 实现请求较为麻烦Service 中还提供一个 getPort 方法通过此方法还可直接实现服务接口 PersonServiceImpl另外Axis 还为准备了一个 ServiceFactory 工厂通过 ServiceFactory 可以直接获取 Service 对象

public static void main(String[] args) throws

RemoteException MalformedURLException ServiceException {

// TODO Autogenerated method stub

HelloWorld()

}

private static void HelloWorld() throws

ServiceException RemoteException MalformedURLException {

String wsdl=;

String uri=;

String serviceName=PersonServiceImplService;

//使用serviceFacotry直接生成服务

ServiceFactory factory=ServiceFactorynewInstance()

Service service=(Service) factorycreateService(

new URL(wsdl)new QName(uriserviceName))

//使用servicegetPort方法实现服务接口

PersonServiceImpl personService=(PersonServiceImpl)service

getPort(PersonServiceImplclass)

String data=oWorld(Leslie

Systemoutprintln(data)

}

以自定义对象传输数据

若需要以自定义对象作为数据传输的载体则需要为自定义对象继承 Serializable 接口另外可以留意一下服务的 wsdl 因为 Axis 并没有默认使用List Map 等类型 在 ListMap 等作为参数时wsdl 都会把返回类型设置为 ArrayOf_xsd_anyType所以建议使用简单数组作为返回值

public class PersonEntity implements Serializable {

private Integer id;

private String name;

private Integer age;

private String address;

public PersonEntity(Integer idString nameInteger ageString address){

thisid=id;

thisname=name;

thisage=age;

thisaddress=address;

}

public Integer getId(){

return id;

}

public void setId(Integer id){

thisid=id;

}

…… } public interface IPersonService {

PersonEntity GetPerson(int id)

PersonEntity[] GetList()

List GetList(String name) } public class PersonServiceImpl implements IPersonService {

@Override

public PersonEntity[] GetList(){

PersonEntity[] list=new PersonEntity[];

PersonEntity person=new PersonEntity(Leslietianhe

PersonEntity person=new PersonEntity(Elvahenan

list[]=person;

list[]=person;

return list;

}

@Override

public List GetList(String name){

List list=new ArrayList()

PersonEntity person=new PersonEntity(name+ Leetianhe

PersonEntity person=new PersonEntity(name+ Chenhenan

listadd(person

listadd(person

return list;

}

@Override

public PersonEntity GetPerson(int id){

return new PersonEntity(idLeslietianhe

} }

在 serverconfigwsdd 中使用 beanMapping 加入自定义对象绑定以 languageSpecificType 绑定类名qname 可由用户设置但必须与 xmln 特性相对应

……

<service name=PersonService provider=java:RPC>

<parameter name=className value=axisserviceImplsPersonServiceImpl />

<parameter name=allowedMethods value=* />

<parameter name=scope value=application />

<beanMapping qname=myNS:PersonEntity xmlns:myNS=urn:PersonEntity

languageSpecificType=java:axisentityPersonEntity />

service>

……

以 WSDLJava 生成客户端代码后可以留意 PersonEntity 对象已经自动实现了 Serializable 接口增加了 getDeserializergetSerializer 等序列化与反序列化方法此时直接使用代理类会自动地完成对象序列化的过程可以节省了不少时间

public static void main(String[] args) throws

RemoteException MalformedURLException ServiceException {

GetList()

GetPerson()

}

private static void GetPerson() throws

RemoteException MalformedURLException{

PersonServiceImpl personService=new PersonServiceSoapBindingStub(

new URL(

new PersonServiceImplServiceLocator())

PersonEntity person=personServicegetPerson(

DisplayPersonProperty(person)

}

private static void GetList() throws

ServiceException RemoteException MalformedURLException{

PersonServiceImpl personService=new PersonServiceSoapBindingStub(

new URL(

new PersonServiceImplServiceLocator())

Object[] objs=personServicegetList(Leslie

for(Object person:objs)

DisplayPersonProperty((PersonEntity)person)

}

//显示对象属性

private static void DisplayPersonProperty(PersonEntity person){

Systemoutprintln(Id:+persongetId()+ Name:+persongetName()+ Age:+

persongetAge()+ Address:+persongetAddress())

}

但需要注意如果使用 Service 类去调用服务的时候需要使用 CallregisterTypeMapping 注册一个类型把接收到的信息转换为 PersonEntity 类型在注册类型时 namespaceURI 参数值需要与服务端 serverconfigwsdd 中的值保持一致

public static void main(String[] args) throws

RemoteException MalformedURLException ServiceException {

// TODO Autogenerated method stub

GetArray()

GetList()

}

private static void GetArray() throws

ServiceException RemoteException{

Service service=new Service()

Call call=(Call)servicecreateCall()

callsetTargetEndpointAddress(

//注册返回类型namespaceURI 必须与服务端注册值一致

QName qName=new QName(urn:PersonEntityPersonEntity

callregisterTypeMapping(PersonEntityclass qName

new BeanSerializerFactory(PersonEntityclassqName

new BeanDeserializerFactory(PersonEntityclassqName))

//绑定请求方法

callsetOperation(GetList

//设置返回类型

callsetReturnClass(PersonEntity[]class)

PersonEntity[] list=(PersonEntity[]) callinvoke(new Object[]{})

for(PersonEntity person:list)

DisplayPersonProperty(person)

}

private static void GetList() throws

ServiceException RemoteException{

Service service=new Service()

Call call=(Call)servicecreateCall()

callsetTargetEndpointAddress(

//注册返回类型namespaceURI 必须与服务端注册值一致

QName qName=new QName(urn:PersonEntityPersonEntity

callregisterTypeMapping(PersonEntityclass qName

new BeanSerializerFactory(PersonEntityclassqName

new BeanDeserializerFactory(PersonEntityclassqName))

//绑定请求方法

callsetOperationName(new javaxxmlnamespac

               

上一篇:Java字节码深入解析

下一篇:Java异常