发布与调用 Web 服务还能再简化吗?

本文是《轻量级 Java Web 框架架构设计》的系列博文。

在 Java 6 以后,发布与调用 Web 服务是一件非常简单的事情,只需使用 JAX-WS(Java API for XML-based Web Services)即可,它也是 JSR-224 规范。大家知道规范都是接口,是没有实现的,不过官方提供了一个参考实现,名为 JAX-WS RI,其中的 RI 是 Reference Implement(参考实现)的意思。

我们可以直接借助 JAX-WS RI 来发布与调用 Web 服务,还等什么?现在就开始!

第一步:下载 JAX-WS RI 程序包

这是一个压缩包,大约 17 M 左右,下载后直接解压即可,比如,解压到 D:\SDK\JAX-WS 目录下。

因为要将服务从 Web 应用里发布出来,而 Web 应用是部署在 Tomcat 上的,但此时 Tomcat 却不知道 JAX-WS RI 在哪里。怎么办呢?不妨对 Tomcat 做一个简单的配置吧。

第二步:配置 Tomcat

打开 TOMCAT\conf\catalina.properties 文件,做如下修改:

common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,D:/SDK/JAX-WS/lib/*.jar

注意:以上红色文字即为所修改的内容。

第三步:配置 Web 服务接口

在 Java 6 中提供了一个 javax.jws 包,所有的 JAX-WS 注解都在该包中。可使用 @WebService 注解配置在 Java 接口上:

import javax.jws.WebService;

@WebService
public interface GreetingService {

    void sayHello(String name);
}

第四步:配置 Web 服务实现

同样适用 @WebService 注解配置 Web 服务实现,不同的是,需要定义两个属性:

import com.smart.sample.service.GreetingService;
import javax.jws.WebService;

@WebService(serviceName = "GreetingService", endpointInterface = "com.smart.sample.service.GreetingService")
public class GreetingServiceImpl implements GreetingService {

    @Override
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }
}

其中,serviceName 属性表示 Web 服务的名称,endpointInterface 属性表示 Web 服务的接口。

为什么叫 endpoint(端点)?其实本质就是一个 Java 接口,只不过在 Web 服务中给它叫了一个高端大气上档次的名字罢了。

第五步:发布 Web 服务

在 WEB-INF 目录下新建一个名为 sun-jaxws.xml 的文件,其内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">

    <endpoint name="GreetingService" url-pattern="/GreetingService" implementation="com.smart.sample.service.impl.GreetingServiceImpl"/>

</endpoints>

以上对 endpoint 起了一个名字(name 属性),配置了 url 匹配地址是什么(url-pattern 属性),此外还指定了一个具体的 Web 服务实现(implementation 属性)。

还要做什么呢?直接启动 Tomcat 吧!

第六步:启动 Tomcat

可使用以下地址查看 Web 服务的 WSDL:

http://localhost:8080/smart-sample/GreetingService?wsdl

WSDL 是 Web Services Description Language 的缩写,说白了就是 Web 服务的描述文件,描述一下这个 Web 服务到底有什么?

发布与调用 Web 服务还能再简化吗?_第1张图片

以上 XML 文档中最重要的就 4 个东西:

  1. Web 服务的名称(name = "GreetingService")
  2. Web 服务的命名空间(targetNamespace="http://impl.service.sample.smart.com/"
  3. Web 服务的地址(location="http://localhost:8080/smart-sample/GreetingService"
  4. Web 服务的方法(见 operation 元素

以上这 4 要素正是 Web 服务客户端需要知道的信息,最后用一个客户端来完成 Web 服务调用。

最后一步:调用 Web 服务

写一个客户端类,用它来调用以上发布的 Web 服务。注意:在调用时可不要关闭 Tomcat 哦!

import com.smart.sample.service.GreetingService;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class GreetingServiceClient {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://localhost:8080/smart-sample/GreetingService?wsdl");
        QName qname = new QName("http://impl.service.sample.smart.com/", "GreetingService");

        Service service = Service.create(url, qname);
        GreetingService greetingService = service.getPort(GreetingService.class);

        greetingService.sayHello("Jack");
    }
}

客户端代码一般分为三步:

  1. 定义相关数据,包括 WSDL 的 URL 地址、Web 服务的 QName(即 Qualified Name,限定名称,可理解为带路径的名称,类似于 Java 中带包名的类)
  2. 获取 Service Port(可理解为调用 Web 服务的代理对象,其实调用 Web 服务的本质上就是代理模式的一种实践)
  3. 调用目标方法(这就是通过代理来调用目标对象的方法)

运行后,就可以在 Tomcat 控制台下看到 Hello Jack 的输出文字了。

够简单吧!我不这么认为。

至少有两个地方是可以简化一下的:

  1. 只需在接口上配置 @WebService,无需在实现上配置。
  2. 无需配置 sun-jaxws.xml,直接在接口上配置即可。

也就是说,发布 Web 服务只需要在一个地方配置,那就是接口!

Smart 又是如何进行简化,让它变得更加优雅的呢?敬请关注。

同时也期待着您更加优秀的解决方案!


补充(2013-11-22)

除了通过 Web 容器(Tomcat)来发布 Web 服务以外,JAX-WS 还提供了另一种发布方式:

import com.smart.sample.service.impl.GreetingServiceImpl;
import javax.xml.ws.Endpoint;

public class GreetingServiceServer {

    public static void main(String[] args) throws Exception {
        Endpoint.publish("http://localhost:8080/smart-sample/GreetingService", new GreetingServiceImpl());
    }
}

JAX-WS 提供了一个 Endpoint 工具类,只需调用它的 publish 方法即可发布 Web 服务。该方法包括 2 个参数:

  1. 第一个参数是 Web 服务的地址。
  2. 第二个参数是 Web 服务的实现。

此方法无需借助 Tomcat,方便客户端测试。

不过对于 Web 应用而言,最直接的方式还是通过 Web 容器来部署比较恰当。

你可能感兴趣的:(发布与调用 Web 服务还能再简化吗?)