什么是 WebService 代理?
WebService 代理 是一个由工具自动生成的 Java 客户端程序,这个客户端程序充当了调用远程 WebService 的“代理人”或“中间层”。

工作流程如下:
- 定义接口:远程 WebService 会有一个标准的接口定义(通常是 WSDL - Web Services Description Language)。
- 生成代理:开发者使用一个工具(如 JDK 自带的
wsimport),提供 WSDL 文件的地址,该工具会分析 WSDL,并自动生成一组 Java 文件,包括:- 一个或多个 Java 接口(Interface),这些接口定义了 WebService 提供的所有方法。
- 这些接口的实现类(通常是一个
Stub或Proxy类)。 - 用于数据交换的 Java Bean(通常用
@XmlRootElement等注解)。 - 一些辅助类,如服务类(Service)。
- 调用服务:在你的 Java 代码中,你不需要关心底层的 SOAP 消息格式、HTTP 传输、XML 编解码等复杂细节,你只需要像调用本地 Java 方法一样,创建代理对象,并调用它提供的方法即可。
- 底层转换:当你调用代理对象的方法时,代理对象会自动完成以下工作:
- 将 Java 方法调用和参数序列化成符合 SOAP 协议的 XML 消息。
- 通过 HTTP 协议将这个 XML 消息发送到远程 WebService 的服务器地址。
- 接收服务器返回的 SOAP 响应 XML 消息。
- 将 XML 响应消息反序列化成 Java 对象,并返回给你的调用代码。
核心优势:将远程调用本地化,极大地简化了开发,让开发者可以专注于业务逻辑,而不是底层的通信细节。
主流技术和工具
在 Java 生态中,主要有两种主流的 WebService 开发/调用模型,它们都支持生成和使用代理:
a. JAX-WS (Java API for XML Web Services)
这是目前 Java 官方、主流的 WebService 标准,它取代了早期的 JAX-RPC。

- 特点:
- 基于标准 SOAP 1.1/1.2 协议。
- 使用注解(如
@WebService,@WebMethod,@WebParam)来简化开发和配置。 - 生成代理的核心工具是
wsimport,它包含在 JDK 的bin目录下。 - 在 Java 6 及以上版本中,JAX-WS API 已经是内置的。
b. Apache CXF
这是一个功能强大、开源的 WebService 框架,它不仅支持 JAX-WS 标准,还支持 RESTful 服务(JAX-RS)。
- 特点:
- 完全实现了 JAX-WS 和 JAX-RS 规范。
- 提供了比标准 JAX-WS 更多的灵活性和扩展性,例如更好的 XML 数据绑定支持、WS-* 标准的实现(如 WS-Security)等。
- 它也使用
wsimport来生成客户端代理,但提供了更多高级功能和工具。 - 在很多企业项目中,CXF 是 JAX-WS 的一个流行替代品或增强实现。
c. Axis2 (较旧)
Axis2 是 Apache 旗下的另一个 WebService 框架,曾经非常流行,但现在,对于新的 SOAP 项目,更推荐使用 JAX-WS 或 CXF,因为它们更符合 Java 标准,生态更成熟。
使用 JAX-WS (wsimport) 生成和使用代理的完整示例
假设我们要调用一个公共的天气查询 WebService。
步骤 1:获取 WSDL 文件地址
找一个公开的 WebService,WebXml.com 上的天气查询服务。
它的 WSDL 地址是:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl

步骤 2:使用 wsimport 生成客户端代码
打开你的命令行(CMD 或 PowerShell),执行以下命令:
# -keep: 生成后保留源文件,方便查看 # -d: 指定编译后的 .class 文件存放目录 # -p: 指定生成的包名 # wsdl_location: 指定 wsdl 文件的最终位置,客户端代码会使用这个地址 wsimport -keep -d . -p com.example.weather.client http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
执行成功后,你会在当前目录下看到 com/example/weather/client 文件夹,里面包含了所有生成的 .java 文件。
步骤 3:将生成的代码集成到你的项目中
- 将
com目录下的所有文件复制到你的 Java 项目的src/main/java目录下。 - 如果你使用 Maven,可以手动编译这些
.java文件,然后将生成的.class文件打包到你的 JAR 中,或者,你也可以将wsimport命令集成到 Maven 的构建生命周期中(稍后介绍)。
步骤 4:编写 Java 代码调用服务
你可以像调用本地方法一样调用 WebService 了,生成的代码中通常会有一个 Service 类,它是你获取代理对象的入口。
package com.example.weather.client;
public class WeatherClient {
public static void main(String[] args) {
// 1. 创建服务对象 (Service)
// 这个类名是根据 WSDL 中的 <service name> 生成的
WeatherWebService service = new WeatherWebService();
// 2. 从服务对象中获取端口 (Port)
// 这个接口名是根据 WSDL 中的 <portType name> 生成的
WeatherWebServiceSoap port = service.getWeatherWebServiceSoap();
// 3. 调用 WebService 方法
// getWeather() 方法需要城市代码作为参数,"北京" 的代码是 "1"
String cityCode = "1";
ArrayOfString weatherInfo = port.getWeather(cityCode, "");
// 4. 处理返回结果
// 返回结果是一个 List<String>,包含了天气信息
if (weatherInfo != null && weatherInfo.getString() != null) {
System.out.println("查询到的天气信息:");
for (String info : weatherInfo.getString()) {
System.out.println(info);
}
} else {
System.out.println("未能获取天气信息。");
}
}
}
运行这段代码,你就可以看到从远程服务器获取的天气数据了。
在 Maven 项目中集成 WebService 代理
手动生成和复制代码很麻烦,Maven 提供了 jaxws-maven-plugin 插件,可以自动化这个过程。
步骤 1:在 pom.xml 中添加插件配置
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version> <!-- 使用较新版本 -->
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase> <!-- 在 generate-sources 阶段执行 -->
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<!-- WSDL 文件的 URL 或本地路径 -->
<wsdlUrls>
<wsdlUrl>http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl</wsdlUrl>
</wsdlUrls>
<!-- 生成的源代码存放目录 -->
<sourceDestDir>${project.build.directory}/generated-sources/jaxws</sourceDestDir>
<!-- 生成的包名 -->
<packageName>com.example.weather.client</packageName>
<!-- 其他 wsimport 参数 -->
<keep>true</keep>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
步骤 2:执行 Maven 命令
在项目根目录下运行:
mvn clean generate-sources
Maven 会自动执行 wsimport,并将生成的 Java 文件放在 target/generated-sources/jaxws 目录下。
步骤 3:将生成的源码加入编译路径
为了让 Maven 编译这些新生成的文件,你需要告诉 Maven 这是一个源代码目录,在 pom.xml 的 <build> 部分添加:
<build>
...
<sourceDirectories>
<sourceDirectory>src/main/java</sourceDirectory>
<!-- 添加生成的源码目录 -->
<sourceDirectory>${project.build.directory}/generated-sources/jaxws</sourceDirectory>
</sourceDirectories>
...
</build>
你就可以直接在项目中像使用普通代码一样使用这些生成的代理类了,IDE 也能正确识别和提供代码提示。
最佳实践和注意事项
-
超时设置:调用远程服务可能会因为网络问题而变慢或超时,务必为你的代理设置合理的连接超时和读取超时。
- 全局设置:通过
System.setProperty设置。// 连接超时 (毫秒) System.setProperty("http.connection.timeout", "5000"); // 读取超时 (毫秒) System.setProperty("http.socket.timeout", "10000"); - 针对特定端点设置:通过
BindingProvider接口。WeatherWebServiceSoap port = service.getWeatherWebServiceSoap(); // BindingProvider 允许你为特定请求配置属性 Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext(); requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 5000); // 5 seconds requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 10000); // 10 seconds
- 全局设置:通过
-
错误处理:调用 WebService 可能会抛出多种异常,如
WebServiceException(网络问题、WSDL 解析错误等)、SOAPFaultException(服务器返回了 SOAP 错误),使用try-catch块妥善处理这些异常。 -
HTTPS 和证书:WebService 是通过 HTTPS 提供的,并且使用了自签名证书或不受信任的 CA 证书,JVM 默认会拒绝连接,你需要配置 SSL 上下文来信任这些证书。
-
性能考虑:每次调用
service.getPort()都会创建一个新的代理实例,如果服务被频繁调用,可以考虑缓存这个代理实例以提高性能。 -
选择技术栈:
- 简单项目/快速集成:直接使用 JDK 自带的
wsimport。 - 企业级项目/需要高级特性:推荐使用 Apache CXF 或 Spring-WS(Spring-WS 采用契约优先,与 JAX-WS 的代码优先不同,也非常强大)。
- 简单项目/快速集成:直接使用 JDK 自带的
| 特性 | 描述 |
|---|---|
| 核心思想 | 将远程 WebService 调用转换为本地 Java 方法调用,隐藏底层 SOAP/XML/HTTP 细节。 |
| 关键技术 | JAX-WS (Java 标准) 和 Apache CXF (功能强大的框架)。 |
| 核心工具 | wsimport (JDK 自带),用于从 WSDL 生成客户端代理代码。 |
| Maven 集成 | 使用 jaxws-maven-plugin 插件,可在构建自动化地生成代码。 |
| 调用方式 | 通过生成的 Service 类获取 Port (接口实现),然后直接调用接口方法。 |
| 关键点 | 超时设置、异常处理、HTTPS 证书配置是实际开发中必须考虑的问题。 |
掌握 WebService 代理的使用,是 Java 开发者进行系统间集成和互操作的一项基本技能。
