- vừa được xem lúc

Cách ngăn việc tuần tự hóa (Serialization) làm phá vỡ mẫu thiết kế Singleton trong Java

0 0 5

Người đăng: Vinh Phạm

Theo Viblo Asia

Singleton là một mẫu thiết kế thường được sử dụng nhằm đảm bảo rằng một lớp chỉ có duy nhất một thể hiện (instance) và cung cấp một điểm truy cập toàn cục đến nó.

Tuy nhiên, quá trình tuần tự hóa (serialization) có thể âm thầm phá vỡ cam kết của Singleton bằng cách tạo ra một thể hiện mới trong quá trình giải tuần tự hóa (deserialization). Trong bài viết này, chúng ta sẽ tìm hiểu lý do tại sao điều này xảy ra và cách khắc phục.

Vấn đề: Serialization phá vỡ Singleton

Hãy bắt đầu với một lớp Singleton cơ bản:

import java.io.*; class Singleton implements Serializable { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; }
}

Bây giờ hãy serialize và deserialize Singleton này:

Singleton instance1 = Singleton.getInstance(); // Serialize to a file
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
out.writeObject(instance1);
out.close(); // Deserialize from the file
ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));
Singleton instance2 = (Singleton) in.readObject();
in.close(); System.out.println(instance1 == instance2); // false ❌

Mặc dù Singleton đã được cài đặt đúng, nhưng quá trình giải tuần tự hóa lại tạo ra một đối tượng mới, phá vỡ tính chất Singleton.

Cách khắc phục: Cài đặt phương thức readResolve()

Java cung cấp một hook có tên là readResolve() cho phép bạn kiểm soát đối tượng được trả về trong quá trình giải tuần tự hóa.

Sửa lại lớp Singleton như sau:

class Singleton implements Serializable { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } // This ensures that deserialization returns the original instance private Object readResolve() throws ObjectStreamException { return instance; }
}

Bây giờ, quá trình serialize và deserialize sẽ giữ đúng thể hiện Singleton:

System.out.println(instance1 == instance2); // true ✅

Ghi chú

  • Phương thức readResolve() phải là private và trả về Object.
  • Nếu không có nó, cơ chế serialization mặc định của Java sẽ tạo ra một thể hiện mới.
  • Luôn kiểm tra kỹ các lớp Singleton nếu chúng cài đặt Serializable.

Bonus: Ngăn chặn các cuộc tấn công thông qua Reflection (Không bắt buộc)

Serialization không phải là mối đe dọa duy nhất với Singleton. Reflection cũng có thể phá vỡ nó.

Bạn có thể ném ra một ngoại lệ trong constructor nếu thể hiện đã tồn tại:

private Singleton() { if (instance != null) { throw new RuntimeException("Use getInstance() method to get the single instance of this class"); }
}

Kết luận

Serialization có thể làm suy yếu mẫu thiết kế Singleton, nhưng readResolve() là một công cụ đơn giản mà hiệu quả để duy trì tính toàn vẹn của Singleton.

Hãy luôn cẩn thận khi đánh dấu một lớp Singleton là Serializable, đặc biệt trong các hệ thống phân tán, bộ nhớ cache, hoặc khi truyền đối tượng qua mạng.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tổng hợp các bài hướng dẫn về Design Pattern - 23 mẫu cơ bản của GoF

Link bài viết gốc: https://gpcoder.com/4164-gioi-thieu-design-patterns/. Design Patterns là gì. Design Patterns không phải là ngôn ngữ cụ thể nào cả.

0 0 326

- vừa được xem lúc

Học Spring Boot bắt đầu từ đâu?

1. Giới thiệu Spring Boot. 1.1.

0 0 294

- vừa được xem lúc

Cần chuẩn bị gì để bắt đầu học Java

Cần chuẩn bị những gì để bắt đầu lập trình Java. 1.1. Cài JDK hay JRE.

0 0 64

- vừa được xem lúc

Sử dụng ModelMapper trong Spring Boot

Bài hôm nay sẽ là cách sử dụng thư viện ModelMapper để mapping qua lại giữa các object trong Spring nhé. Trang chủ của ModelMapper đây http://modelmapper.org/, đọc rất dễ hiểu dành cho các bạn muốn tìm hiểu sâu hơn. 1.

0 0 205

- vừa được xem lúc

[Java] 1 vài tip nhỏ khi sử dụng String hoặc Collection part 1

. Hello các bạn, hôm nay mình sẽ chia sẻ về mẹo check String null hay full space một cách tiện lợi. Mình sẽ sử dụng thư viện Lớp StringUtils download file jar để import vào thư viện tại (link).

0 0 84

- vừa được xem lúc

Deep Learning với Java - Tại sao không?

Muốn tìm hiểu về Machine Learning / Deep Learning nhưng với background là Java thì sẽ như thế nào và bắt đầu từ đâu? Để tìm được câu trả lời, hãy đọc bài viết này - có thể kỹ năng Java vốn có sẽ giúp bạn có những chuyến phiêu lưu thú vị. DJL là tên viết tắt của Deep Java Library - một thư viện mã ng

0 0 157