杰瑞科技汇

Java序列化如何与WebService结合使用?

  1. 核心概念:什么是序列化?WebService 为什么需要它?
  2. 传统 WebService (JAX-WS) 与 Java 序列化:这是它们最直接的关系。
  3. 现代 WebService (RESTful / JAX-RS) 与序列化:情况发生了变化。
  4. Java 序列化的优缺点:为什么现在不推荐在 WebService 中使用它。
  5. 最佳实践和替代方案:我们应该用什么来替代 Java 序列化?

核心概念

什么是序列化?

在 Java 中,序列化 的过程是将 Java 对象转换成一种可以存储或传输的格式(通常是字节流),反序列化 则是相反的过程,将字节流重新还原成原来的 Java 对象。

Java序列化如何与WebService结合使用?-图1
(图片来源网络,侵删)
// 序列化: 对象 -> 字节流
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序列化如何与WebService结合使用?-图2
(图片来源网络,侵删)

在这种模式下,关系如下:

Java 对象 -> Java 序列化机制 -> XML (SOAP) -> 网络传输

详细流程:

  1. 服务端

    • 你定义一个 Java 接口,用 @WebService 注解标记它。
    • 实现这个接口,你的方法参数和返回值都是普通的 Java 对象(POJO)。
    • 当客户端调用这个 WebService 方法时,JAX-WS 框架会自动介入。
  2. 序列化过程 (服务端)

    Java序列化如何与WebService结合使用?-图3
    (图片来源网络,侵删)
    • 框架获取你方法返回的 Java 对象(User 对象)。
    • 它会使用 Java 内置的序列化机制(ObjectOutputStream 的底层逻辑)来将对象图转换成字节流。
    • 它将这些字节流包装进一个符合 SOAP 规范的 XML 文档中,这个 XML 文档被称为 SOAP 消息,它包含了方法名、参数、返回值以及被序列化后的对象数据。
  3. 网络传输

    这个 SOAP 消息(本质是 XML 字符串)通过 HTTP 协议发送给客户端。

  4. 反序列化过程 (客户端)

    • 客户端接收到 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 -> 网络传输

详细流程:

  1. 服务端

    • 你定义一个 Java 类(POJO),User
    • 在 JAX-RS 资源方法中,直接返回这个 User 对象。
    • @Produces(MediaType.APPLICATION_JSON) 注解告诉客户端,我返回的是 JSON 格式。
  2. 序列化过程 (服务端)

    • JAX-RS 框架(如 Jersey, RESTEasy)检测到返回的是一个 Java 对象,并且媒体类型是 JSON。
    • 它会调用一个 JSON Binding 库(最常用的是 Jackson,还有 Gson, Moxy)。
    • Jackson 库会读取 User 类的字段(通过反射),然后将它们转换成 JSON 格式的字符串。
    • 这个 JSON 字符串作为 HTTP 响应体发送给客户端。
  3. 网络传输

    JSON 字符串通过 HTTP 协议发送。

  4. 反序列化过程 (客户端)

    • 客户端接收到 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 中不推荐)

优点:

  1. 简单:Java 内置,Serializable 接口无脑实现即可。
  2. 保真度高:可以完整地序列化一个复杂的对象图,包括引用关系。

缺点(致命的,尤其在 WebService 场景下):

  1. 非跨语言:这是最大的问题,Java 序列化产生的字节流是 Java 特有的,其他语言(如 Python, C++, JavaScript)无法直接解析,这违背了 WebService 跨平台的核心原则。
  2. 安全性风险:反序列化是 Web 攻击的重灾区,攻击者可以构造恶意的字节流,在反序列化时执行任意
分享:
扫描分享到社交APP
上一篇
下一篇