Java 직렬화

What - 직렬화가 무엇일까?

Java 내부 시스템에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 Byte 형태로 변환하는 기술 + 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)

JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태

How - 직렬화를 어떻게 사용할까?

직렬화 조건

Primitive 타입과 java.io.Serializable 인터페이스를 상속받은 객체는 직렬화 할 수 있는 기본 조건을 가진다.

직렬화 방법

java.io.ObjectOutputStream 객체 이용

역직렬화 조건

  • 직렬화 대상이 된 객체의 클래스가 클래스 패스에 존재해야 하며 import 되어 있어야 한다.

    • 중요 포인트 : 직렬화와 역직렬화를 진행하는 시스템이 서로 다를 수 있다는 것을 반드시 고려해야 한다.
  • 직렬화 대상 객체는 동일한 serialVersionUID 를 가지고 있어야 한다.

Why - 직렬화를 왜 사용할까?

데이터 직렬화 종류

  • 문자열 형태의 직렬화 방법

    • 범용적인 API나 데이터를 변환하여 추출할 때 많이 사용
    • CSV, JSON
  • 이진 직렬화 방법

    • 데이터 변환 및 전송 속도에 최적화하여 별도의 직렬화 방법을 제시하는 구조
    • Protocol Buffer, Apache Avro

자바 직렬화 형태의 데이터 교환은 자바 시스템 간의 데이터 교환을 위해서 존재한다.

자바에서도 CSV, JSON을 사용하면 되지 자바 직렬화를 써야 되는 이유? => 목적에 따라 적절하게 써야 한다.

자바 직렬화의 장점 : 자바 시스템에서 개발에 최적화되어 있다.

When, Where - 언제 어디서 사용될까?

JVM의 메모리에서만 상주되어있는 객체 데이터를 그대로 영속화(Persistence)가 필요할 때 사용된다. 시스템이 종료되더라도 없어지지 않는 장점을 가지며 영속화된 데이터이기 때문에 네트워크로 전송도 가능하다. 필요할 때 직렬화된 객체 데이터를 가져와서 역직렬화하여 객체를 바로 사용할 수 있다.

  • 서블릿 세션 (Servlet Session)

    • 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만, 파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달된다. (세션에 필요한 객체는 Serializable 인터페이스를 구현해두는 것을 추천!)
  • 캐시 (Cache)

    • 캐시를 이용하면 DB에 대한 리소스를 절약할 수 있기 때문에 많은 시스템에서 자주 활용된다. 이렇게 캐시할 부분을 자바 직렬화된 데이터를 저장할 때 사용된다. 자바 직렬화만 이용해서 캐시를 저장하지 않지만 가장 간편하다.
  • 자바 RMI (Remote Method Invocation)

    • 원격 시스템 간의 메시지 교환을 위해서 사용하는 자바에서 지원하는 기술 (최근에는 많이 사용되지 않음)
    • 원격의 시스템의 메서드를 호출 시에 전달하는 메시지(객체)를 자동으로 직렬화시켜 사용된다.

실무에서는?

serialVersionUID

객체의 해시코드로 직렬화될 때 객체에 표시되는 식별자 역할 - 객체의 버전 관리에 사용된다.

직렬화/역직렬화를 할 때 이 값으로 해당 클래스의 특정 버전에 맞는지 아닌지를 판단한다.

객체의 해시코드로 직렬화될 때 객체에 표시되는 식별자 역할

  • SUID(serialVersionUID)가 필수 값은 아니다.
  • 호환 가능한 클래스는 SUID값이 고정되어 있다.
  • SUID가 선언되어 있지 않으면 클래스의 기본 해쉬값을 사용한다. (해쉬값 알고리즘은 링크에서 확인이 가능합니다.)

직접 serialVersionUID 값을 관리해주어야 클래스 변경 시 혼란을 줄일 수 있다. 하지만 serialVersionUID 값이 동일할 때에도 신경 써야 할 부분이 생긴다.

  1. 멤버 변수명은 같은데 멤버 변수 타입이 바뀔 때
  2. 직렬화 자바 데이터에 존재하는 멤버 변수를 없애거나 추가했을 때

자바 직렬화는 타입에 상당히 엄격하다

자바 직렬화를 사용할 때 클래스 구조 변경 시 확인해야할 점

  • serialVersionUID 값은 개발 시 직접 관리해야 한다.
  • serialVersionUID 값이 동일하면 멤버 변수 및 메서드 추가는 크게 문제가 없다. 멤버 변수 제거 및 이름 변경은 오류는 발생하지 않지만 데이터는 누락된다.
  • 역직렬화 대상의 클래스의 멤버 변수 타입 변경을 지양해야 한다.
  • 외부(DB, 캐시 서버, NoSQL 서버 등)에 장기간 저장될 정보는 자바 직렬화 사용을 지양해야 한다. 긴 시간동안 외부에 존재했던 직렬화된 데이터는 쓰레기(Garbage)가 될 가능성이 높다.
  • 개발자가 직접 컨트롤이 가능한 클래스의 객체가 아닌 클래스의 객체에 대해서는 직렬화를 지양해야 한다.

정리

  1. 외부 저장소로 저장되는 데이터는 짧은 만료시간의 데이터를 제외하고 자바 직렬화를 사용을 지양한다.
  2. 역직렬화 시 반드시 예외가 생긴다는 것을 생각하고 개발한다.
  3. 자주 변경되는 비즈니스적인 데이터를 자바 직렬화을 사용하지 않는다.
  4. 긴 만료 시간을 가지는 데이터는 JSON 등 다른 포맷을 사용하여 저장한다.

참고


Written by@Myunghwan
Nothing changes if nothing changes

GitHub