这是一个非常经典且重要的主题,因为 Java 在 WebService 的发展史上扮演了至关重要的角色,我会从核心概念、主流技术演进、具体实现和现代替代方案四个方面来详细讲解。

核心概念:什么是 WebService?
在深入 Java 技术之前,我们先要明白 WebService 是什么。
WebService 是一种跨编程语言、跨操作系统平台的远程调用技术,它使用 HTTP 协议作为传输协议,使用 XML 或 JSON 等格式来封装和传输数据。
它的核心目标是实现“系统间的通信”,尤其是在异构系统(比如用 Java 写的后端和用 Python 写的后端)之间。
WebService 的主要特点:

- 跨平台:只要能发送 HTTP 请求和解析 XML/JSON,任何语言都可以调用。
- 跨语言:与语言无关。
- 基于标准:遵循一系列国际标准(如 SOAP, WSDL),保证了互操作性。
- 松耦合:服务调用方和服务提供方之间不需要了解对方的内部实现细节,只需要知道接口规范(WSDL)。
Java WebService 技术演进
Java 的 WebService 技术经历了几个重要的阶段,每个阶段都有其代表性的技术和框架。
JAX-WS (Java API for XML Web Services) - 目前企业级应用的主流
这是 Java 官方推出的、用于创建和消费 SOAP (Simple Object Access Protocol) WebService 的标准 API,它极大地简化了 WebService 的开发。
- 核心思想:通过注解将一个普通的 Java 类变成一个 WebService 服务端。
- 关键注解:
@WebService: 将一个类标记为 WebService 服务端。@WebMethod: 将一个方法标记为 WebService 的可操作方法。@WebParam: 定义方法的参数。
- 优点:
- 标准化:Java EE 的标准,实现厂商多,兼容性好。
- 工具支持:通过
wsimport命令可以一键根据 WSDL 文件生成客户端调用代码,非常方便。 - 契约优先:可以先定义 WSDL 契约,然后生成服务端和客户端的“骨架代码”。
- 缺点:
- 主要用于 SOAP 协议,相对复杂和“重量级”。
- 配置相对繁琐。
代表实现:
- JDK 内置实现:从 JDK 1.6 开始,JAX-WS API 就被内置了,可以直接使用
Endpoint类来发布服务。 - Apache CXF:一个非常流行和强大的开源框架,对 JAX-WS 提供了完美的支持,功能更丰富,性能更好。
- Metro:由 Sun (Oracle) 官方提供的实现,也包含在 GlassFish 等应用服务器中。
JAX-RS (Java API for RESTful Web Services) - 现代 Web 开发的事实标准
虽然 JAX-RS 严格来说不属于传统意义上的“WebService”(因为它通常不使用 SOAP/WSDL),但它在功能上实现了跨系统调用的核心目标,并且已经成为现代 Java Web 开发的主流,所以必须在这里重点介绍。

- 核心思想:将一个普通的 Java 类通过注解变成一个 RESTful 风格的 Web 服务(通常返回 JSON 或 XML)。
- 关键注解:
@Path: 定义资源的 URI 路径。@GET,@POST,@PUT,@DELETE: 定义 HTTP 方法。@Produces: 定义响应的媒体类型(如MediaType.APPLICATION_JSON)。@Consumes: 定义可接受的请求媒体类型。@PathParam,@QueryParam,@FormParam: 用于获取路径参数、查询参数和表单数据。
- 优点:
- 轻量级:基于 HTTP 协议,无冗余的 SOAP 信封,性能高。
- 简单易用:学习曲线平缓,开发效率高。
- 无状态:符合 REST 架构风格,易于缓存和扩展。
- 与前端完美契合:现代前后端分离架构的首选。
- 缺点:
- 没有 WSDL 这样的“标准契约”,接口文档需要通过 Swagger (OpenAPI) 等工具来生成和维护。
- 不适合需要事务、安全等复杂 WS-* 标准的场景。
代表实现:
- Jersey:由 Oracle 赞助的 JAX-RS 的参考实现。
- RESTEasy:JBoss (Red Hat) 提供的 JAX-RS 实现。
- Apache CXF:同样支持 JAX-RS,并且可以和它的 JAX-WS 功能无缝集成。
早期技术 (了解即可)
在 JAX-WS 之前,Java 社区还有一些早期的 WebService 技术。
- JAX-RPC (Java API for XML-based RPC)
JAX-WS 的前身,现在已经过时,被 JAX-WS 完全取代。
- Axis / Axis2 (来自 Apache)
在 JAX-WS 标准普及之前,Axis 是 Java 领域最流行的 WebService 框架,Axis2 是其重构后的版本,功能强大,但配置和使用比 JAX-WS 复杂,现在仍有项目在使用,但新项目已很少选择。
具体实现示例
下面我们通过代码来感受一下 JAX-WS 和 JAX-RS 的开发方式。
示例1:JAX-WS 服务端与客户端
服务端 (JAX-WS)
我们创建一个简单的服务,提供一个根据用户名查询用户信息的功能。
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.WebParam;
// @WebService 注解将这个类声明为一个 WebService
@WebService
public class UserService {
// @WebMethod 注解将这个方法暴露为 WebService 的一个操作
@WebMethod
public User getUserInfo(@WebParam(name = "username") String username) {
System.out.println("服务端收到请求,查询用户: " + username);
// 模拟数据库查询
if ("admin".equals(username)) {
return new User("admin", "管理员", "admin@example.com");
} else if ("zhangsan".equals(username)) {
return new User("zhangsan", "张三", "zhangsan@example.com");
}
return null;
}
}
// 一个简单的 POJO,作为数据载体
class User {
private String username;
private String fullName;
private String email;
// 构造方法、getter 和 setter
public User(String username, String fullName, String email) {
this.username = username;
this.fullName = fullName;
this.email = email;
}
// ... 省略 getter 和 setter ...
@Override
public String toString() {
return "User{" + "username='" + username + '\'' + ", fullName='" + fullName + '\'' + ", email='" + email + '\'' + '}';
}
}
发布服务:你可以写一个 main 方法来发布这个服务。
import javax.xml.ws.Endpoint;
public class Publisher {
public static void main(String[] args) {
// 创建服务实例
UserService userService = new UserService();
// 发布服务,地址为 http://localhost:8080/userService
String address = "http://localhost:8080/userService";
Endpoint.publish(address, userService);
System.out.println("WebService 已发布在: " + address);
}
}
运行后,访问 http://localhost:8080/userService?wsdl,你就能看到服务的 WSDL 契约文件。
客户端 (JAX-WS)
客户端的开发有两种方式:
-
使用 wsimport 工具生成代码 (推荐)
在命令行中执行:
wsimport -s . http://localhost:8080/userService?wsdl
这会在当前目录下生成一堆 Java 文件(服务端接口、Service 类等),然后你就可以像调用本地方法一样调用远程服务了。
// wsimport 生成的代码 public class Client { public static void main(String[] args) { // 创建服务视图 UserService_Service service = new UserService_Service(); // 获取服务端点 UserService userServicePort = service.getUserServicePort(); // 调用远程方法 User user = userServicePort.getUserInfo("admin"); System.out.println("客户端收到响应: " + user); } } -
使用 Dispatch API (更灵活,适合动态调用)
import javax.xml.namespace.QName; import javax.xml.ws.Dispatch; import javax.xml.ws.Service; import javax.xml.transform.stream.StreamSource; import java.net.URL; public class DynamicClient { public static void main(String[] args) throws Exception { URL wsdlUrl = new URL("http://localhost:8080/userService?wsdl"); QName serviceName = new QName("http://default/", "UserService_Service"); Service service = Service.create(wsdlUrl, serviceName); // 使用 Dispatch API,直接操作 XML 消息 Dispatch<StreamSource> dispatch = service.createDispatch( new QName("http://default/", "UserService"), StreamSource.class, Service.Mode.PAYLOAD ); // 构造 SOAP 请求体 (简化版) String request = "<ns2:getUserInfo xmlns:ns2=\"http://default/\"><username>zhangsan</username></ns2:getUserInfo>"; // 发送请求 StreamSource response = dispatch.invoke(new StreamSource(new StringReader(request))); // 解析响应 XML... System.out.println("收到动态响应: " + response); } }
示例2:JAX-RS (Jersey) 服务端与客户端
服务端 (JAX-RS)
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
// @Path 定义了这个资源的 URI 基础路径
@Path("/api/users")
public class UserResource {
// @GET 表示这是一个处理 GET 请求的方法
// @Path("info/{username}") 定义了子路径
// @PathParam("username") 将路径中的 {username} 绑定到方法参数
// @Produces(MediaType.APPLICATION_JSON) 指定返回的数据类型是 JSON
@GET
@Path("info/{username}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser(@PathParam("username") String username) {
System.out.println("REST 服务收到请求,查询用户: " + username);
if ("admin".equals(username)) {
return new User("admin", "管理员", "admin@example.com");
}
return null;
}
}
发布服务:通常需要运行在一个 Web 容器(如 Tomcat, Jetty)或应用服务器(如 Jersey 自带的 Grizzly)中,配置一个 web.xml 或使用 Jersey 的 ResourceConfig。
客户端 (JAX-RS)
同样可以使用 Jersey 客户端 API 来调用。
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
public class RestClient {
public static void main(String[] args) {
// 创建客户端
Client client = ClientBuilder.newClient();
// 定义目标资源地址
WebTarget target = client.target("http://localhost:8080/my-app/api/users/info/admin");
// 发送 GET 请求,并期望返回 JSON
Response response = target.request(MediaType.APPLICATION_JSON).get();
// 检查响应状态
if (response.getStatus() == 200) {
// 将响应体直接映射为 User 对象
User user = response.readEntity(User.class);
System.out.println("REST 客户端收到响应: " + user);
} else {
System.out.println("请求失败,状态码: " + response.getStatus());
}
// 关闭客户端
client.close();
}
}
如何选择?现代趋势
| 特性 | JAX-WS (SOAP) | JAX-RS (REST) |
|---|---|---|
| 协议 | SOAP (基于 XML) | HTTP (通常用 JSON) |
| 风格 | 面向操作 | 面向资源 |
| 复杂度 | 高,信封、头、WS-* 标准 | 低,简单直接 |
| 性能 | 较低 | 较高 |
| 标准化 | 高 (WSDL, SOAP, WS-Security 等) | 较低 (依赖 OpenAPI/Swagger 文档) |
| 安全性 | 内置标准安全机制 (WS-Security) | 通常依赖 HTTPS 和 OAuth/JWT |
| 适用场景 | 企业级应用、金融、电信等对事务、安全、可靠性要求极高的场景 | 现代 Web 应用、微服务、前后端分离架构、移动端 API |
| 发展趋势 | 传统行业存量维护 | 绝对主流,新项目的首选 |
总结与建议:
-
新项目首选 JAX-RS:除非你有非常特殊的需求(比如必须和某个旧的 SOAP 系统深度集成,或者银行等强监管行业要求使用 WS-Security),否则对于所有新的 Java Web 服务开发,都应该毫不犹豫地选择 JAX-RS,它与微服务、云原生、前后端分离等现代开发理念完美契合。
-
JAX-WS 仍有价值:JAX-WS 并没有完全消亡,它仍然在许多大型企业(特别是银行、保险、电信)的核心系统中扮演着重要角色,维护这些系统的存量代码需要掌握 JAX-WS。
-
框架选择:
- 做 JAX-RS,Spring Boot + Spring Web MVC 是目前最强大的组合(虽然 Spring MVC 不完全等同于 JAX-RS,但其 RESTful 开发模式已成为事实标准)。
- 如果想用纯 JAX-RS 规范,Jersey 和 RESTEasy 都是优秀的选择。
- 做 JAX-WS,Apache CXF 是功能最全面、生态最好的选择。
-
未来展望:随着 gRPC、GraphQL 等新技术的兴起,RESTful API 也面临挑战,但就目前而言,JAX-RS (REST) 仍然是 Java 生态中构建跨服务 API 的基石,了解这些技术的演进脉络,能帮助你更好地做出技术选型。
