- 核心概念:什么是序列化?WebService 为什么需要它?
- 传统 WebService (JAX-WS) 与 Java 序列化:这是它们最直接的关系。
- 现代 WebService (RESTful / JAX-RS) 与序列化:情况发生了变化。
- Java 序列化的优缺点:为什么现在不推荐在 WebService 中使用它。
- 最佳实践和替代方案:我们应该用什么来替代 Java 序列化?
核心概念
什么是序列化?
在 Java 中,序列化 的过程是将 Java 对象转换成一种可以存储或传输的格式(通常是字节流),反序列化 则是相反的过程,将字节流重新还原成原来的 Java 对象。

// 序列化: 对象 -> 字节流
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.dat"))) {
User user = new User("Alice", 30);
oos.writeObject(user);
}
// 反序列化: 字节流 -> 对象
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.dat"))) {
User user = (User) ois.readObject();
System.out.println(user.getName()); // 输出: Alice
}
WebService 为什么需要序列化?
WebService 的核心思想是跨平台、跨语言的通信,客户端(可能是用 Python、C#、JavaScript 写的)和服务器端(用 Java 写的)通常运行在不同的环境中,它们之间无法直接传递 Java 对象。
必须有一个“中间人”格式来承载数据,这个格式需要:
- 标准化:被各种语言广泛支持。
- 自描述:接收方不需要预先知道数据结构,也能解析出数据。
序列化就是将 Java 对象转换成这种标准格式的第一步。
传统 WebService (JAX-WS) 与 Java 序列化
当我们谈论 "Java 序列化" 和 "WebService" 的经典组合时,我们通常指的是 SOAP (Simple Object Access Protocol) WebService,它由 javax.xml.ws.* (JAX-WS) API 来实现。

在这种模式下,关系如下:
Java 对象 -> Java 序列化机制 -> XML (SOAP) -> 网络传输
详细流程:
-
服务端:
- 你定义一个 Java 接口,用
@WebService注解标记它。 - 实现这个接口,你的方法参数和返回值都是普通的 Java 对象(POJO)。
- 当客户端调用这个 WebService 方法时,JAX-WS 框架会自动介入。
- 你定义一个 Java 接口,用
-
序列化过程 (服务端):
(图片来源网络,侵删)- 框架获取你方法返回的 Java 对象(
User对象)。 - 它会使用 Java 内置的序列化机制(
ObjectOutputStream的底层逻辑)来将对象图转换成字节流。 - 它将这些字节流包装进一个符合 SOAP 规范的 XML 文档中,这个 XML 文档被称为 SOAP 消息,它包含了方法名、参数、返回值以及被序列化后的对象数据。
- 框架获取你方法返回的 Java 对象(
-
网络传输:
这个 SOAP 消息(本质是 XML 字符串)通过 HTTP 协议发送给客户端。
-
反序列化过程 (客户端):
- 客户端接收到 SOAP 消息(XML)。
- JAX-WS 客户端框架会解析这个 XML 文档。
- 它提取出方法返回值的字节数据部分。
- 使用 Java 内置的反序列化机制(
ObjectInputStream的底层逻辑)将这些字节数据还原成一个 Java 对象(User对象)。
关键点:在 JAX-WS 中,Java 序列化是内部实现细节,开发者通常不直接调用 writeObject/readObject,而是由框架自动完成,它将 Java 对象映射到 SOAP/XML 结构。
示例代码 (简化概念)
服务端接口:
import javax.jws.WebService;
@WebService
public interface UserService {
User getUserById(String id);
}
服务端实现:
import javax.jws.WebService;
@WebService(endpointInterface = "com.example.UserService")
public class UserServiceImpl implements UserService {
@Override
public User getUserById(String id) {
// ... 从数据库查询 ...
User user = new User("zhangsan", 25);
return user; // 框架会自动将这个 user 对象序列化为 SOAP/XML
}
}
客户端调用后,收到的 SOAP 响应可能长这样:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getUserByIdResponse xmlns:ns2="http://example.com/">
<return>
<name>zhangsan</name>
<age>25</age>
</return>
</ns2:getUserByIdResponse>
</soap:Body>
</soap:Envelope>
注意:虽然看起来是 XML,但在 JAX-WS 的底层处理中,Java 对象到字节的转换确实用到了 Java 序列化的算法。
现代 WebService (RESTful / JAX-RS) 与序列化
更主流的 WebService 架构是 RESTful (Representational State Transfer),它通常使用 JSON 作为数据交换格式,由 javax.ws.rs.* (JAX-RS) API 实现。
在这种情况下,Java 序列化不再是主角。
Java 对象 -> JSON 序列化库 (如 Jackson, Gson) -> JSON -> 网络传输
详细流程:
-
服务端:
- 你定义一个 Java 类(POJO),
User。 - 在 JAX-RS 资源方法中,直接返回这个
User对象。 - 用
@Produces(MediaType.APPLICATION_JSON)注解告诉客户端,我返回的是 JSON 格式。
- 你定义一个 Java 类(POJO),
-
序列化过程 (服务端):
- JAX-RS 框架(如 Jersey, RESTEasy)检测到返回的是一个 Java 对象,并且媒体类型是 JSON。
- 它会调用一个 JSON Binding 库(最常用的是 Jackson,还有 Gson, Moxy)。
- Jackson 库会读取
User类的字段(通过反射),然后将它们转换成 JSON 格式的字符串。 - 这个 JSON 字符串作为 HTTP 响应体发送给客户端。
-
网络传输:
JSON 字符串通过 HTTP 协议发送。
-
反序列化过程 (客户端):
- 客户端接收到 JSON 字符串。
- JAX-RS 客户端框架调用 JSON Binding 库(如 Jackson)。
- Jackson 将 JSON 字符串解析,并根据目标 Java 类(
User)的字段名和类型,创建并填充一个User对象实例。
关键点:在 RESTful WebService 中,我们使用的是 JSON (或 XML) 序列化,而不是 Java 原生的对象序列化,开发者通常会选择一个成熟的 JSON 库来处理这个过程。
示例代码 (JAX-RS + Jackson)
服务端资源:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/users")
public class UserResource {
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON) // 告诉框架,我要返回 JSON
public User getUserById() {
User user = new User("lisi", 28);
return user; // 框架会自动用 Jackson 将 user 对象转为 JSON
}
}
客户端调用后,收到的 HTTP 响应体是纯 JSON:
{
"name": "lisi",
"age": 28
}
Java 序列化的优缺点(为什么在 WebService 中不推荐)
优点:
- 简单:Java 内置,
Serializable接口无脑实现即可。 - 保真度高:可以完整地序列化一个复杂的对象图,包括引用关系。
缺点(致命的,尤其在 WebService 场景下):
- 非跨语言:这是最大的问题,Java 序列化产生的字节流是 Java 特有的,其他语言(如 Python, C++, JavaScript)无法直接解析,这违背了 WebService 跨平台的核心原则。
- 安全性风险:反序列化是 Web 攻击的重灾区,攻击者可以构造恶意的字节流,在反序列化时执行任意
