Tuesday, April 5, 2016

Web service summary

JAVA 中共有三种WebService 规范,分别是JAXM&SAAJ、JAX-WS(JAX-RPC)、JAX-RS
1. JAX-WS:
JAX-WS(Java API For XML-WebService),JDK1.6 自带的版本为JAX-WS2.1,其底层支
持为JAXB。
JAX-WS(JSR 224)规范的API 位于javax.xml.ws.*包,其中大部分都是注解,提供API 操
作Web 服务(通常在客户端使用的较多,由于客户端可以借助SDK 生成,因此这个包中的
API 我们较少会直接使用)。
WS-MetaData(JSR 181)是JAX-WS 的依赖规范,其API 位于javax.jws.*包,使用注解配
置公开的Web 服务的相关信息和配置SOAP 消息的相关信息。
2. JAXM&SAAJ:
JAXM(JAVA API For XML Message)主要定义了包含了发送和接收消息所需的API,相当
于Web 服务的服务器端,其API 位于javax.messaging.*包,它是JAVA EE 的可选包,因此
你需要单独下载。
SAAJ(SOAP With Attachment API For Java,JSR 67)是与JAXM 搭配使用的API,为构建
SOAP 包和解析SOAP 包提供了重要的支持,支持附件传输,它在服务器端、客户端都需要
使用。这里还要提到的是SAAJ 规范,其API 位于javax.xml.soap.*包。
JAXM&SAAJ 与JAX-WS 都是基于SOAP 的Web 服务,相比之下JAXM&SAAJ 暴漏了SOAP
更多的底层细节,编码比较麻烦,而JAX-WS 更加抽象,隐藏了更多的细节,更加面向对
象,实现起来你基本上不需要关心SOAP 的任何细节。那么如果你想控制SOAP 消息的更
多细节,可以使用JAXM&SAAJ,目前版本为1.3。
3. JAX-RS:
JAX-RS 是JAVA 针对REST(Representation State Transfer)风格制定的一套Web 服务规范,
由于推出的较晚,该规范(JSR 311,目前JAX-RS 的版本为1.0)并未随JDK1.6 一起发行,
你需要到JCP 上单独下载JAX-RS 规范的接口,其API 位于javax.ws.rs.*包。
这里的JAX-WS 和JAX-RS 规范我们采用Apache CXF 作为实现,默认CXF
是依赖于Spring 的,Bus 都有一个ID,默认的BUS 的ID 是cxf。你要注意的是Apache CXF
2.2 的发行包中的jar 你如果直接全部放到lib 目录,那么你必须使用JDK1.6,否则会报
JAX-WS 版本不一致的问题。对于JAXM&SAAJ 规范我们采用JDK 中自带的默认实现。


1. JAX-WS:
@WebService
public interface IHelloService
...
使用类级别注解@WebService 就标注了这个接口的方法
将公开为Web 服务,使用了这个注解的接口的所有方法都将公开为Web 服务的操作,如果
你想屏蔽某个方法,可以使用方法注解@Method 的exclude=true。我们也通常把公开为Web
服务的接口叫做SEI(Service EndPoint Interface)服务端点接口。

public class HelloServiceImpl implements IHelloService
这个实现类没有任何特殊之处,但是如果你的实现类还实现了其他的接口,那么你需要在实
现类上使用@WebService 注解的endpointInterface 属性指定那个接口是SEI(全类名)

Endpoint.publish("http://127.0.0.1:8080/helloService",
new HelloServiceImpl());
你可能会差异,我们没有
借助Tomcat 这样的Web 服务器,直接运行一个main 方法是怎么发布的Web 服务呢?其实
CXF 内置了Jetty(Servlet 容器),因此你不需要将你的程序部署到Tomcat 等Web 服务器
也可以正常发布Web 服务。

如果你的某些注解的header=true,那么它将被放到
<soap:Header …中传输,而不是SOAP 消息正文
如果是OUT、INOUT 类型的参数类型,这样的方法参数将会被当做返回值在Web 服务调
用完成后返回给你,客户端生成代码时会被转变为javax.xml.ws.Holder<T>类

JAX-WS 中的服务端的自定义异常使用javax.xml.ws.WebFault 注解来完成,这样的异常会在
WSDL 文件中的<wsdl:operation …中的子元素生成<wsdl:fault …

2. JAVA的 WebService规范 JAX-RS
REST 是一种软件架构模式,只是一种风格,不是像SOAP 那样本身承载着一种消息协议,
(两种风格的Web 服务均采用HTTP 做传输协议是因为HTTP 协议能穿越防火墙,JAVA
的远程调用RMI 等是重量级协议,不能穿越防火墙)
。REST 中重要的两个概念就是资源定位和资源操作,而HTTP 协议恰好完
整的提供了这两个要点,HTTP 协议中的URI 可以完成资源定位,GET、POST、OPTION
等方法可以完成资源操作,因此REST 完全依赖HTTP 协议就可以完成Web 服务,而不像
SOAP 协议那样只利用HTTP 的传输特性,定位与操作由SOAP 协议自身完成,也正是由于
SOAP 消息的存在,使得SOAP 笨重。你也可以说REST 充分利用了HTTP 协议的特性,而
不是像SOAP 那样只利用了其传输这一特性
REST 简单易用,
效率高,SOAP 成熟度较高,安全性较好。
REST 提供的网络服务叫做OpenAPI,它不仅把HTTP 作为传输协议,也作为处理数据的工
具,可以说对HTTP 协议做了较好的诠释,充分体现了HTTP 技术的网络能力。目前Google、
Amazon、淘宝都有基于REST 的OpenAPI 提供调用。
JAX-RS 的API 在javax.ws.rs.*包中,其中大部分也是注解。
访问REST 风格的Web 服务很简单,你完全不需要像SOAP 使用SDK 生成客户端代码,因
为REST 完全依赖HTTP 协议, 从这里可见REST 是轻量级的。
你可
以用((HttpURLConnection)new URL(“***”).openConnection()).getInputStream()获取,然
后使用程序处理这个接收到的结果。为了更加好的使用HTTP 访问REST 服务,推荐你使用Apache HttpComponents-Client 组件进行HTTP 操作,因为这里使用的示例是GET 方法的请
求,你是用URL 直接访问或者使用java.net.URL 类来访问很容易,但是如果Web 服务的方
法使用@PUT 等注解,那么你就需要费一番头脑来在请求报头中加入要请求的方法类型等
信息,这些是很繁琐的事情
前面我们都是使用了HTTP-Components-Client 的API 来访问REST 服务,这也是比较干净
的方式,所谓干净就是完全依赖HTTP 的API(其实更加干净的方式就是使用JAVA 自带的
HTTP 的API 操作) , 但是过于干净的调用方式总会很麻烦( 很明显使用
HTTP-Components-Client 要比java.net.*下面的API 要来得简单),其实CXF 自带的
org.apache.cxf.jaxrs.client.WebClient 用起来更加简单。
常用的安全策略机制:
I.传统的用户名令牌机制:
Apache WSS4J(WebService Security For Java)实现了JAVA 语言的WS-Security,CXF 中使
用WSS4J 也是很容易的,WSS4J 依赖于SAAJ。
II.数字签证方法:
除了UsernameToken 这种传统的安全机制,常用的验证动作还有一个就是使用数字签证技
术(X.509 Certificates),
III.混合验证方法:
WSS4J 支持如下几种验证模式:
XML Security
XML Signature
XML Encryption
这两种验证模式都是使用数字签证技术。
Tokens
Username Tokens
Timestamps
SAML Tokens

Web 服务的调用默认都是阻塞调用,但是JAX-WS 也支持异步调用。
因为在Future 的get()方法被调用之前,它不会产生阻
塞,这样你可以在方法执行的最后再去获取异步计算的结果。那么你可能会问,这样整个方
法还是不能算作完全的异步调用,因为最后要返回值的时候还是会阻塞哦!其实有返回值的
Web 服务调用本就不应该使用异步调用,因为返回值通常你都是要拿回来立即使用的。这
种异步调用机制适合于无返回值的Web 服务调用,这样你就不需要再调用Future 的get()方
法了。
如果你想有返回值的时候也进行异步调用,那么就只能使用最原始的开启新的线程的方法,
也就是将Web 服务方法的调用放在run()方法中执行。

实SAAJ 提供的API 就是用于组装和解构
SOAP 消息的。

使用JAXM发布Web服务:
JAXM 的API 实际上就是用来将一个Servlet 发布成WebService 的地址,它要求你的Servlet
继承javax.xml.messaging.JAXMServlet 并实现javax.xml.messaging.ReqRespListener 接口(如
果Web 服务是单向的, 也就是没有返回值给客户端, 那么可以实现
javax.xml.messaging.OnewayListener 接口),其实这一个抽象类和两个接口是我们可以使用
的三个JAXM 的API,其余的基本上都是JAXM 底层实现需要使用的API,我们并不需要
关心。
在实际应用中,你可以把你的业务层放在onMessage()方法中调用,相当于把业务层的方法
用这个Servlet 包装成了Web 服务,这个Servlet 不可以使用普通的方式访问,只能使用
SoapConnection 的call()方法调用。
实际上你可以看出来,JAXM 发布的Web 服务比较简单,完全省略了WSDL,这也就是说,
你用这种方式发布Web 服务,必须把要接收的Soap 消息的内容说明发布出来(有点儿类似
于REST 风格的OpenAPI),这样客户端才知道如何组装你想要的SOAP 消息。从这里你也
可以看出来,HTTP 协议与SOAP 消息是基于SOAP 的基本组成,WSDL 是完全可以没有的,
WSDL 的作用是异构平台为了方便使用自己的语言特性的中间桥梁。




No comments:

Post a Comment