杰瑞科技汇

Java如何调用WebService?

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

Java如何调用WebService?-图1
(图片来源网络,侵删)

概览:三种主要方式

  1. Spring Boot (Spring Web + Feign Client) - 现代、首选

    • 特点:这是目前最流行、最现代化的方式,它不关心 WebService 的具体实现技术(如 SOAP 还是 REST),而是通过一个简单的声明式接口来调用,代码简洁、易于维护,与 Spring 生态系统无缝集成。
    • 适用场景:几乎所有基于 Spring Boot 的新项目。
  2. JAX-WS (Java API for XML Web Services) - 传统、标准

    • 特点:这是 Java 官方提供的、用于创建和调用 SOAP WebService 的标准 API,它非常稳定,但配置相对繁琐,代码侵入性较强。
    • 适用场景:需要与遗留系统交互,或者项目要求使用标准的 SOAP 协议。
  3. Apache CXF - 强大、灵活

    • 特点:这是一个功能强大的开源框架,它既支持 JAX-WS 标准,也支持 JAX-RS (RESTful WebService),可以看作是 JAX-WS 的一个超集,提供了更多高级功能和灵活性。
    • 适用场景:当 JAX-WS 的标准功能无法满足需求,或者需要在一个框架中同时处理 SOAP 和 REST 服务时。

Spring Boot + Feign Client (推荐)

这种方式的核心思想是 “面向接口编程”,你只需要定义一个接口,并用注解描述如何调用远程服务,Spring Boot 会自动为你生成实现类并完成所有底层网络通信。

Java如何调用WebService?-图2
(图片来源网络,侵删)

步骤 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 注解来指定要调用的服务地址。

Java如何调用WebService?-图3
(图片来源网络,侵删)

假设我们要调用一个公共的天气查询 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 文件(如 ServicePortTypeXXX 等)。

步骤 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,它是一个“瑞士军刀”,能解决很多棘手问题。
分享:
扫描分享到社交APP
上一篇
下一篇