시냅스

Java 코드로 알아보는 직렬화와 역직렬화 본문

Java, Spring

Java 코드로 알아보는 직렬화와 역직렬화

ted k 2023. 2. 28. 22:49

자바 직렬화 (Java Serialization)

 

https://www.geeksforgeeks.org/serialization-in-java/

 

  • 자바 객체를 바이트 스트림으로 변환하여 파일이나 네트워크 상에서 전송 가능하도록 만드는 것
    • 자바 객체는 주소 값을 가지고 있고 이는 프로세스가 새로 실행될 때 마다 변하는 값이다.
    • 프로세스를 새로 실행했을 때 해당 객체에 대한 주소가 같을 거라는 보장이 없다.
    • 따라서 객체(혹은 레퍼런스 타입)에 대한 데이터를 외부에 저장하고 싶다면 직렬화가 필요하다.
  • 직렬화된 객체는 다시 역직렬화(Deserialization)하여 객체로 변환될 수 있다.
    • 역직렬화를 할 때에는 몇가지 조건이 필요하다.
      • 직렬화 대상의 클래스가 class path 에 존재하며 import 되어 있어야 한다.
      • 동일한 버전 (serialVersionId) 를 유지해야 한다.
        • 만약 serialVersionId을 선언하지 않았다면 내부 클래스 구조 정보를 이용하여 자동으로 생성된 해시 값이 할당된다.
        • 따라서 멤버 변수 등이 추가/삭제 된다면 자동으로 버전은 바뀌게 된다.
  • 객체를 전송 가능한 형태로 만들어줌으로써 객체를 쉽게 공유할 수 있다.
  • Serializable 인터페이스를 구현하여 변환 가능하다.
    • Serializable 인터페이스는 마커 인터페이스로 표시하기만 한다.
  • 사용처
    • 객체를 파일이나 데이터베이스에 저장하고 싶을 때
    • 객체를 네트워크를 통해 전송하고 싶을 때 (Servlet Session)
    • 객체를 메모리에 캐시하여 재사용하고 싶을 때 (Redis 등)
    • 객체를 복제하고 싶을 때

 

직렬화의 종류

  • Text 기반 직렬화
    • 객체를 text 형태로 변환하여 저장하는 방식
    • CSV, XML, JSON 등
    • 직렬화된 데이터를 읽고 디버깅 하기 용이하다.
    • 사람이 읽을 수 있을 수 있는 형태로 저장되므로 다른 시스템과의 호환성이 높다.
    • 다만 데이터 크기가 크고 직렬화/역직렬화 속도가 느리다.
  • 2진(Binary) 기반 직렬화
    • 효율적인 저장 및 전송이 가능하다.
    • 다만 직렬화된 데이터를 사람이 확인하기 어렵다.

 

 

직렬화 코드 예제

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}
  • 예제로 사용할 Person 객체이다.

 

2진 (binary) 기반

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person p1 = new Person("lilt", 30);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);

        // Person 객체를 직렬화하여 objectOutputStream에 쓰기
        objectOutputStream.writeObject(p1);

        // 직렬화된 데이터를 바이트 배열로 변환
        byte[] bytes = byteArrayOutputStream.toByteArray();

        // 직렬화된 데이터 출력을 위해 InputStream 사용
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bais);

        // 역직렬화된 Person 객체를 읽어온다.
        Person deserialized = (Person) ois.readObject();

        System.out.println(deserialized.getName()); // lilt
        System.out.println(deserialized.getAge()); // 30

        ois.close();
        bais.close();
        objectOutputStream.close();
        byteArrayOutputStream.close();
    }
}
  • 2진 기반 직렬화로 outputstream을 사용하여 byte 배열로 생성한다.
  • 이후 역직렬화를 위해 inputstream을 사용하여 간단하게 객체를 확인할 수 있다.

 

text 기반

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = new Person("lilt", 30);
        String json = objectMapper.writeValueAsString(person);
        System.out.println(json); // {"name":"lilt","age":30}

        Person deserialized = objectMapper.readValue(json, Person.class);
        System.out.println(deserialized.getName());
        System.out.println(deserialized.getAge());
    }
}
  • text 기반은 json 을 예시로 한다.
  • 또한 jackson 라이브러리를 사용하여 간편하게 구현할 수 있다.
  • 역직렬화를 할 때에는 밸류와 원하는 클래스를 파라미터로 넘겨 원하는 객체를 얻어올 수 있다.
  • 다만 역직렬화를 할 때에는 프록시 등의 이유로 기본 생성자를 필요로 한다.
Comments