目录
- 核心概念
- 什么是 CXF?
- 调用 WebService 的两种主要方式
- 准备工作:环境搭建
添加 CXF 依赖
(图片来源网络,侵删) - 使用 WSDL 文件(推荐)
- 步骤 1:获取 WSDL 文件
- 步骤 2:使用
wsdl2java工具生成客户端代码 - 步骤 3:编写 Java 代码调用服务
- 完整示例
- 动态调用(无需生成客户端代码)
- 介绍
- 步骤 1:创建
JaxWsDynamicClientFactory - 步骤 2:创建客户端并调用方法
- 完整示例
- 高级配置
- 添加 SOAP Header(安全认证等)
- 处理超时问题
- 总结与对比
核心概念
什么是 CXF?
Apache CXF 是一个开源的 Services 框架,它支持构建和开发 WebService,它支持多种协议和数据绑定,包括 SOAP、XML/HTTP、RESTful HTTP 以及 CORBA,对于 Java CXF 提供了与 Spring 框架深度集成的能力。
调用 WebService 的两种主要方式
-
静态客户端(代码生成方式)
- 原理:根据 WebService 的 WSDL (Web Services Description Language) 文件,使用 CXF 提供的工具 (
wsdl2java) 自动生成一系列 Java 代码(如 Service、PortType、数据模型类等)。 - 优点:
- 代码类型安全,编译器可以检查错误。
- 开发体验好,有代码提示,易于调试。
- 生成的代码封装了所有细节,调用非常简单。
- 缺点:
- 需要一个额外的代码生成步骤。
- WSDL 发生变化,需要重新生成代码。
- 适用场景:WSDL 接口稳定,项目长期维护,推荐使用此方式。
- 原理:根据 WebService 的 WSDL (Web Services Description Language) 文件,使用 CXF 提供的工具 (
-
动态客户端
- 原理:不生成任何客户端代码,而是在程序运行时通过 WSDL 动态地解析服务接口,并直接调用。
- 优点:
- 无需代码生成过程,开发快速。
- 非常灵活,适合处理 WSDL 可能变化或需要动态调用不同服务的场景(如测试工具)。
- 缺点:
- 代码不够类型安全,所有参数和返回值都是
Object类型,需要手动强制类型转换。 - 调试相对困难。
- 代码不够类型安全,所有参数和返回值都是
- 适用场景:快速原型开发、测试工具、脚本化调用。
准备工作:环境搭建
你需要在你的 Java 项目中添加 CXF 的依赖,这里以 Maven 为例。

在你的 pom.xml 文件中添加以下依赖:
<dependencies>
<!-- CXF 核心依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.4.5</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- CXF 的 Jetty 依赖,如果需要内嵌服务器,但这里客户端不需要 -->
<!-- <dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.4.5</version>
</dependency> -->
<!-- 日志依赖,CXF 依赖 SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
方式一:使用 WSDL 文件(推荐)
假设我们要调用一个简单的天气查询服务,它的 WSDL 地址是:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
步骤 1:获取 WSDL 文件
直接在浏览器中访问上面的 URL,会看到一个 XML 文件,这就是 WSDL,将它保存到本地,weather.wsdl,或者直接使用网络 URL。
步骤 2:使用 wsdl2java 工具生成客户端代码
CXF 提供了一个命令行工具 wsdl2java,它可以根据 WSDL 文件生成客户端代码。

下载 CXF 压缩包
从 Apache CXF 官网 下载二进制压缩包(apache-cxf-3.4.5.zip),并解压。
设置环境变量
将解压后的 bin 目录添加到系统的 PATH 环境变量中,这样你就可以在任何地方使用 wsdl2java 命令。
运行命令 打开命令行(CMD 或 PowerShell),切换到你的项目根目录(或者一个专门存放生成代码的目录),然后执行以下命令:
wsdl2java -p com.example.weather.client -d src/main/java -client http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl
命令参数解释:
-p com.example.weather.client:指定生成的 Java 包名。-d src/main/java:指定代码生成的目标目录(Maven 项目的标准目录)。-client:生成一个可以独立运行的客户端测试类。- WSDL 文件的 URL 或本地路径。
执行成功后,你会在 src/main/java/com/example/weather/client 目录下看到一堆生成的 .java 文件,其中最重要的是:
WeatherWebService.java:服务接口。WeatherWebServiceService.java:服务工厂类,用于获取服务接口实例。ArrayOfString.java:数据模型类,用于封装请求和响应数据。
步骤 3:编写 Java 代码调用服务
你可以在你的 Java 代码中像调用本地方法一样调用 WebService 了。
package com.example.weather.client;
public class WeatherServiceClient {
public static void main(String[] args) {
// 1. 创建服务工厂实例
// WeatherWebServiceService 是 wsdl2java 生成的工厂类
WeatherWebServiceService service = new WeatherWebServiceService();
// 2. 获取服务端点接口
// WeatherWebService 是 wsdl2java 生成的服务接口
WeatherWebService weatherWebService = service.getWeatherWebServiceSoap();
try {
// 3. 调用 WebService 方法
// 假设服务有一个 getWeather 方法,需要城市名作为参数
// 注意:根据实际生成的接口,方法名和参数可能不同
// 这里我们调用获取支持的城市列表的方法
String[] cities = weatherWebService.getSupportCity("重庆");
// 4. 处理返回结果
System.out.println("支持的城市列表:");
if (cities != null) {
for (String city : cities) {
System.out.println(city);
}
}
// 调用获取天气信息的方法
// 参数格式:城市名, 如 "重庆"
// 返回的是一个复杂对象,需要根据生成的类来解析
// ArrayOfString weatherInfo = weatherWebService.getWeather("重庆");
// System.out.println("\n重庆的天气信息:" + weatherInfo.getString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行这个 main 方法,如果一切正常,你就能看到从 WebService 返回的数据。
方式二:动态调用(无需生成客户端代码)
这种方式不需要 wsdl2java 步骤,适合快速测试。
package com.example.weather.dynamic;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsDynamicClientFactory;
import org.apache.cxf.endpoint.Client;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.URL;
public class DynamicWeatherClient {
public static void main(String[] args) {
// 1. 创建动态客户端工厂
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
// 2. 创建客户端,指定 WSDL 地址
// 第二个参数是服务的命名空间,可以在 WSDL 的 <definitions> 标签的 targetNamespace 属性找到
// 第三个参数是服务名 