Java - 직렬화

<이펙티브 자바>

Posted by Yan on May 21, 2021

객체 직렬화

  • 자바가 객체를 바이트 스트림으로 인코딩하고 (직렬화)
  • 그 바이트 스트림으로부터 다시 객체를 재구성하는 (역직렬화) 매커니즘
  • 직렬화된 객체는 다른 VM에 전송하거나 디스크에 저장한 수 나중에 역직렬화할 수 있다.

    자바 시스템 내부에서 사용되는 객체 또는 데이터를
    외부의 자바 시스템에서도 사용할 수 있도록
    바이트 형태로 데이터를 변환하는 기술과
    바이트로 변환된 데이터를 다시 객체로 전환하는 기술을 아울러서 이야기한다.

JVM의 메모리에 상주되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과,
직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 의미한다.

직렬화가 가능한 클래스 Serializable

  • 자바는 Serializable인터페이스를 구현한 클래스만 직렬화할 수 있도록 제한하고 있다.
  • Serializable인터페이스는 필드나 메소드가 없는 빈 인터페이스지만, 객체를 직렬화할 때 private필드를 포함한 모든 필드를 바이트로 변환해도 좋다는 표시 역할을 한다.
1
public class XXX implements Serializable { }
  • 객체를 직렬화하면 바이트로 변환되는 것은 필드들이고, 생성자 및 메소든느 직렬화에 포함되지 않는다.
  • 따라서 역직렬화할 때에는 필드의 값만 복원된다.
  • 하지만 모든 필드가 직렬화 대상이 되는 것은 아니다. 필드 선언에 transient가 붙어 있을 경우에는 직렬화가 되지 않는다.
1
2
3
4
5
6
public class ClassA implements Serializable {
    int field1; //직렬화 가능
    ClassB field2 = new ClassB(); //직렬화 가능
    static int field3; // 직렬화 가능
    transient int field4; // 직렬화에서 제외
}
1
2
3
public class ClassB implements Serializable {
    int field1; // 직렬화에 포함
}

직렬화의 장점

  • 자바 시스템에서 개발에 최적화되어 있다.
    복잡한 데이터 구조의 클래스 객체라도 직렬화 기본 조건만 지키면 큰 작업 없이 바로 직렬화가 가능하다.
  • 데이터 타입이 자동으로 맞춰지기 때문에 관련 부분에 신경을 쓰지 않아도 된다.
  • 역직렬화가 되면 바로 기존 객체처럼 사용할 수 있다.

직렬화의 문제

  • 직렬화의 근본적인 문제는 공격 범위가 너무 넓고 지속적으로 더 넓어져 방어하기 어렵다는 점이다.
  • ObjectInputStreamreadObject 메소드를 호출하면서 객체 그래프가 역직렬화되기 때문이다.
  • readObjet메소드는 (Serializable 인터페이스를 구현했다면) 클래스패스 안의 거의 모든 타입의 객체를 만들어낼 수 있는 생성자다.
    • 바이트 스트림을 역직렬화하는 과정에서 이 메소드는 그 타입들 안의 모든 코드를 수행할 수 있다.
    • 즉, 그 타입들의 코드 전체가 공격 범위에 들어간다는 뜻이다.

언제 쓰는건가?

  • JVM의 메모리에만 상주되어있는 객체 데이터를 그대로 영속화가 필요할 때 사용된다.
    시스템이 종료되더라도 없어지지 않는 장점을 가진다.
    영속화된 데이터이기 때문에 네트워크로 전송도 가능하다.
  • Servelet Session
    서블릿 기반의 WAS(톰캣)들은 대부분 세션의 자바 직렬화를 지원한다.
    파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화되어 저장되어 전달된다.
  • Cache
  • JAVA RMI(Remote Method Invocation)

참고자료