我将为您详细介绍三种主流的方法,从最现代、最推荐的方式开始,逐步介绍到更传统的方式。

概览:三种主要方式
-
Spring Boot (Spring Web + Feign Client) - 现代、首选
- 特点:这是目前最流行、最现代化的方式,它不关心 WebService 的具体实现技术(如 SOAP 还是 REST),而是通过一个简单的声明式接口来调用,代码简洁、易于维护,与 Spring 生态系统无缝集成。
- 适用场景:几乎所有基于 Spring Boot 的新项目。
-
JAX-WS (Java API for XML Web Services) - 传统、标准
- 特点:这是 Java 官方提供的、用于创建和调用 SOAP WebService 的标准 API,它非常稳定,但配置相对繁琐,代码侵入性较强。
- 适用场景:需要与遗留系统交互,或者项目要求使用标准的 SOAP 协议。
-
Apache CXF - 强大、灵活
- 特点:这是一个功能强大的开源框架,它既支持 JAX-WS 标准,也支持 JAX-RS (RESTful WebService),可以看作是 JAX-WS 的一个超集,提供了更多高级功能和灵活性。
- 适用场景:当 JAX-WS 的标准功能无法满足需求,或者需要在一个框架中同时处理 SOAP 和 REST 服务时。
Spring Boot + Feign Client (推荐)
这种方式的核心思想是 “面向接口编程”,你只需要定义一个接口,并用注解描述如何调用远程服务,Spring Boot 会自动为你生成实现类并完成所有底层网络通信。

步骤 1:添加依赖
在你的 pom.xml 文件中添加 spring-cloud-starter-openfeign 依赖。
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- OpenFeign Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 如果你的 WebService 返回的是 JSON (RESTful),这个依赖很重要 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
注意:你需要确保 Spring Cloud 的版本与 Spring Boot 版本兼容。
步骤 2:启用 Feign 客户端
在你的 Spring Boot 启动类上添加 @EnableFeignClients 注解。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients // 启用 Feign 客户端功能
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}
步骤 3:定义 Feign 客户端接口
创建一个接口,使用 @FeignClient 注解来指定要调用的服务地址。

假设我们要调用一个公共的天气查询 API(这是一个 RESTful 服务,但 Feign 同样适用)。
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
// name: 服务名称,通常用于服务发现,如果直接调用,可以写服务地址。
// url: 直接指定服务的完整 URL。
@FeignClient(name = "weatherService", url = "http://weather.example.com")
public interface WeatherServiceClient {
// 这个方法定义需要和远程服务的 API 完全一致
@GetMapping("/api/weather")
String getWeather(@RequestParam("city") String city);
}
步骤 4:在 Service 中注入并调用
现在你可以在任何 Spring 管理的 Bean(如 Service)中注入这个接口并直接调用方法。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WeatherReportService {
private final WeatherServiceClient weatherServiceClient;
// 通过构造器注入 Feign 客户端
@Autowired
public WeatherReportService(WeatherServiceClient weatherServiceClient) {
this.weatherServiceClient = weatherServiceClient;
}
public String getCityWeather(String cityName) {
// 直接调用接口方法,就像调用本地方法一样
String weatherData = weatherServiceClient.getWeather(cityName);
System.out.println("从远程获取到的天气数据: " + weatherData);
return "北京的天气是: " + weatherData;
}
}
优点:
- 代码简洁:业务代码与网络调用代码完全分离。
- 易于测试:可以轻松地创建 Mock 对象来测试业务逻辑。
- 高度集成:完美融入 Spring 生态,支持负载均衡、熔断器等。
JAX-WS (标准 SOAP)
这种方式更偏向于传统的 SOAP (Simple Object Access Protocol) WebService。
步骤 1:获取 WSDL 文件
所有 SOAP 服务都会提供一个 WSDL (Web Services Description Language) 文件,它描述了服务的接口、方法、参数和返回值,通常是一个 URL,http://example.com/service?wsdl。
步骤 2:使用 JDK 自带工具生成客户端代码
打开命令行,进入你的项目目录,执行以下命令:
wsimport -keep -p com.example.client http://example.com/service?wsdl
-keep: 生成源代码。-p com.example.client: 指定生成的 Java 包名。
执行后,会在 com.example.client 包下生成一堆 Java 文件(如 Service、PortType、XXX 等)。
步骤 3:编写调用代码
生成的代码中,你会找到一个 Service 类(WeatherService),用它来创建服务端点,然后调用具体方法。
import com.example.client.WeatherService; // 这是 wsimport 生成的 Service 类
import com.example.client.WeatherServiceSoapType; // 这是 wsimport 生存的 PortType 接口
public class JaxwsClient {
public static void main(String[] args) {
// 1. 创建服务 Service 实例
WeatherService service = new WeatherService();
// 2. 获取服务端口 (Port),这是实际调用的入口
// "WeatherServiceSoap" 是 WSDL 中定义的端口名称
WeatherServiceSoapType port = service.getWeatherServiceSoap();
// 3. 调用远程方法
String result = port.getWeather("Beijing");
// 4. 处理结果
System.out.println("通过 JAX-WS 获取到的天气: " + result);
}
}
优点:
- 标准化:是 Java 官方标准,兼容性好。
- 工具成熟:
wsimport工具非常稳定。
缺点:
- 配置繁琐:需要手动执行命令生成代码。
- 代码侵入性强:生成的代码与 JAX-WS API 紧耦合。
- 性能相对较低:基于 XML,比 JSON/REST 更重。
Apache CXF
CXF 是一个功能更全面的框架,你可以用它来创建客户端,也可以用它来创建服务端。
步骤 1:添加依赖
在 pom.xml 中添加 CXF 的依赖。
<dependencies>
<!-- CXF 核心依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.4.5</version> <!-- 使用最新稳定版本 -->
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.4.5</version>
</dependency>
</dependencies>
步骤 2:创建客户端
CXF 提供了两种主要方式创建客户端:
A. 使用 WSDL 生成客户端 (与 JAX-WS 类似)
CXF 也提供了类似的代码生成工具 cxf-codegen-plugin (Maven 插件) 或 wsdl2java 命令行工具,它们比 JDK 的 wsimport 功能更强大,生成的代码也更好用,步骤与 JAX-WS 类似,这里不再赘述。
B. 动态客户端 (更灵活)
动态客户端不需要提前生成任何 Java 代码,而是直接在运行时根据 WSDL 创建调用。
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
public class CxfDynamicClient {
public static void main(String[] args) {
// 1. 创建 JaxWsProxyFactoryBean
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// 2. 设置服务接口 (可以从 wsdl 中获取,或者使用生成的接口)
// 假设我们知道有一个 IWeatherService 接口
// factory.setServiceClass(IWeatherService.class);
// 如果没有接口,可以直接设置 WSDL 地址
factory.setAddress("http://example.com/service?wsdl");
// 3. 创建客户端代理
Object client = factory.create();
// 假设我们知道调用的方法名和参数
// IWeatherService weatherService = (IWeatherService) client;
// String result = weatherService.getWeather("Beijing");
// 4. 或者通过更通用的方式调用
try {
// 使用反射调用方法
Object result = client.getClass().getMethod("getWeather", String.class).invoke(client, "Beijing");
System.out.println("通过 CXF 动态客户端获取到的天气: " + result);
} catch (Exception e) {
e.printStackTrace();
}
// 5. (可选) 设置超时等连接属性
Client proxy = ClientProxy.getClient(client);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setConnectionTimeout(10000); // 10秒连接超时
policy.setReceiveTimeout(10000); // 10秒接收超时
conduit.setClient(policy);
}
}
优点:
- 功能强大:支持 SOAP 1.1/1.2, REST, CORBA 等。
- 灵活性高:动态客户端无需生成代码。
- 可扩展性强:提供了很多拦截器、数据绑定等高级功能。
缺点:
- 学习曲线稍陡:比 Feign 和原生 JAX-WS 更复杂。
总结与选择建议
| 特性 | Spring Boot + Feign | JAX-WS (标准) | Apache CXF |
|---|---|---|---|
| 核心思想 | 声明式接口,面向接口编程 | 标准化,基于 WSDL 生成代码 | 功能强大的框架,支持多种协议 |
| 易用性 | 非常高,最简洁 | 中等,需要手动生成代码 | 中等,配置选项多 |
| 主要用途 | RESTful API,也适用于 SOAP | 传统 SOAP 服务 | SOAP, REST, CORBA 等复杂场景 |
| 与现代集成 | 极佳,与 Spring 生态完美融合 | 一般,属于传统技术 | 良好,但不如 Feign 无缝 |
| 推荐场景 | 新项目首选,尤其是 Spring 项目 | 遗留系统维护,或强制使用 SOAP 的项目 | 需要处理多种协议或高级特性的项目 |
如何选择?
- 如果你正在开发一个新的 Spring Boot 项目:毫不犹豫选择 Spring Boot + Feign,它会让你事半功倍,代码非常优雅。
- 如果你需要对接一个老旧的、基于 SOAP 的系统:使用 JAX-WS,它是标准,稳定可靠,JAX-WS 的灵活性不够,再考虑 Apache CXF。
- 如果你的项目非常复杂,需要在一个框架中同时处理 SOAP 和 REST 服务:选择 Apache CXF,它是一个“瑞士军刀”,能解决很多棘手问题。
