Languages/Java

[Java] 직렬화 (Serialization)

dbssk 2023. 7. 31. 23:59

직렬화(Serialization)

자바의 직렬화는 객체를 바이트 형태로 변환하는 기술을 말한다. 이를 통해 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 변환하여 전송하거나 저장할 수 있다.

 

직렬화/역직렬화 과정

// Employee라는 클래스를 정의 
// Serializable 인터페이스를 구현함으로써 이 클래스의 객체는 직렬화 가능함을 나타냄
import java.io.Serializable;

public class Employee implements Serializable {
    private String name;
    private int id;

    // getters, setters 생략
}

위 객체를 직렬화하는 코드

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeExample {
    public static void main(String[] args) {
        Employee e = new Employee(); // 직렬화할 Employee 객체를 생성
        e.setName("John");
        e.setId(101);

        try {
            // 객체를 저장할 파일을 위한 FileOutputStream을 생성
            FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser");
            
            // ObjectOutputStream을 생성하여 Employee 객체를 직렬화하고 파일에 쓰기
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(e);
            
            // 스트림 닫기
            out.close();
            fileOut.close();
            
            System.out.println("Serialized data is saved in /tmp/employee.ser");
        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

이렇게 직렬화된 객체를 다시 역직렬화하는 코드

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class DeserializeExample {
    public static void main(String[] args) {
        Employee e = null; // 역직렬화한 객체를 저장할 변수를 선언

        try {
            // 직렬화된 객체가 저장된 파일을 위한 FileInputStream을 생성
            FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
            
            // ObjectInputStream을 생성하여 파일로부터 객체를 읽어와서 역직렬화
            ObjectInputStream in = new ObjectInputStream(fileIn);
            e = (Employee) in.readObject();
            
            // 스트림을 닫기
            in.close();
            fileIn.close();
        } catch (IOException i) {
            i.printStackTrace();
        } catch (ClassNotFoundException c) {
            System.out.println("Employee class not found");
            c.printStackTrace();
        }

        // 역직렬화된 객체의 정보를 출력
        System.out.println("Deserialized Employee...");
        System.out.println("Name: " + e.getName());
        System.out.println("ID: " + e.getId());
    }
}

 

직렬화 시 주의사항

  • 'serrialVersionUID'는 직렬화된 객체와 해당 객체의 클래스 정의가 일치하는지 검증하기 위해 사용되는 ID이다. 클래스의 정의가 변경되면 이 ID가 달라져 역직렬화가 실패할 수 있다. 따라서 클래스를 변경할 때 이 ID를 명시적으로 관리하는 것이 좋다.
  • 직렬화된 객체는 클래스의 private 필드까지 모두 포함하므로, 부적절하게 역직렬화된 경우 보안 문제가 발생할 수 있다.
  • Serializable 인터페이스를 구현하지 않은 클래스의 객체를 직렬화 하려고 하면 'java.io.NotSerializableException'이 발생한다. 또한, 직렬화 가능한 클래스의 필드 중에서 특정 필드를 직렬화에서 제외하려면 그 필드를 'transient'로 선언해야 한다.
  • 개발자가 직접 컨트롤할 수 없는 클래스, 자주 변경되는 클래스는 직렬화 사용을 지양한다.
  • 역직렬화에 실패하는 상황에 대한 예외처리는 필수로 구현한다.
  • 직렬화 데이터는 타입, 클래스 메타정보를 포함하므로 사이즈가 크다. 트래픽에 따라 비용 증가 문제가 발생할 수 있기 때문에 JSON 포맷으로 변경하는 것이 좋다.

 

[참고] https://gyoogle.dev/blog/computer-language/Java/Serialization.html