2. 직렬화

직렬화(Serialization)

직렬화란 데이터 구조나 오브젝트 상태를 동일하거나 다른 컴퓨터 환경에 저장하고 나중에 재구성할 수 있는 포멧으로 변환하는 과정이다 직렬화와 역직렬화를 통해 객체 또는 데이터의 복사본을 만들 수 있다.

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

문자열 형태의 serialize

직접 데이터를 문자열 형태로 확인 가능한 직렬화로 표 형태의 데이터를 직렬화시 CSV가 많이 쓰이고 구조데이터는 JSON 형태를 많이 사용한다. CSV 형태는 Apache Commons CSV, opencsv 등의 라이브러리를 많이 쓰고 JSON 형태는 Jackson, GSON의 라이브러리를 이용해서 변환할 수 있다.

이진 데이터의 serialize

데이터 변환 및 전송속도에 최적화된 직렬화 방법으로 Protocol Butter, Apache Avro 등이 존재한다.

자바의 serialize

자바 직렬화 형태의 데이터 교환은 자바 시스템 간의 데이터 교환을 위해 존재한다. 주로 사용되는 곳은

  • 서블릿 세션

    • WAS에서 대부분의 세션이 자바 직렬화를 지원한다.

    • 파일 저장, 세션 클러스터링, DB저장에서 세션 자체가 직렬화되어 저장된다.

  • 캐시

    • Ehcache, Redis, Memcached 등의 캐시 라이브러리에서 사용한다.

  • RMI

    • 원격 시스템의 메서드 호출 시에 전달하는 메시지를 자동으로 직렬화해서 사용한다.

등이 있다. 기본적으로 자바에서는 Serializable를 Implements 해줌으로써 명시할 수 있다.

타 서버로 SerialDto를 전송한다고 가정해보면 전송하는 서버와 전송 받는 서버 모두 SerialDto가 존재해야 한다. 그런데 만약 SerialDto변수가 여러개 있으면 자바가 제대로 처리하지 못한다. 그런 상황을 대비해 객체의 식별을 위해 serialVersionUID를 따로 관리해줘야 한다. 클래스 이름, UID, 변수의 객체나 타입이 모두 같아야지만 같은 클래스로 인식된다. 만약 지정하지 않는다면 컴파일러에 의해 자동으로 생성된다. 자바에서 객체를 저장하기 위해 ObjectOutputStream을 사용하면 된다.

public class SerialDto implements Serializable {
    private static final long serialVersionUID = 1L;
    private String bookName;
    private int bookOrder;
    private boolean bestSeller;
    private long soldPerDay;

    public SerialDto(String bookName, int bookOrder, boolean bestSeller, long soldPerDay) {
        super();
        this.bookName = bookName;
        this.bookOrder = bookOrder;
        this.bestSeller = bestSeller;
        this.soldPerDay = soldPerDay;
    }

    @Override
    public String toString() {
        return "SerialDto [bookName=" + bookName + ", bookOrder=" + bookOrder
                + ", bestSeller=" + bestSeller + ", soldPerDay=" + soldPerDay + "]";
    }
}

public static void main(String[] args) {
    ManageObject manager = new ManageObject();
    String fullPath = "dumpFile" + separator + "text.txt";
    SerialDto dto = new SerialDto("book1", 1, true, 100);
    manager.saveObject(fullPath, dto);
}
public void saveObject(String fullPath, SerialDto dto) {
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;

    try {
        fos = new FileOutputStream(fullPath);
        oos = new ObjectOutputStream(fos);
        oos.writeObject(dto);
        System.out.println("write Success");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if(oos != null) {
            try {
                oos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(fos != null) {
            try {
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Wrtie()메서드를 사용해 int 값을 지정하고 writeByte()로 바이트 값을 저장하면 된다.

transient

추가로 transient 예약어가 있는데 선었한 객체 필드에 transient를 선언해주면 해당 필드는 직렬화되지 않는다.

주의해야할 포인트

  • serialVersionUID는 필수값이 아니지만 컴파일러 구현에 따라 달라질 수 있으므로 꼭 적어주자

  • SUID가 선언되어 있지 않으면 클래스의 기본 해쉬값을 이용한다.

  • 클래스의 필드 속성이 바뀌면 역직렬화에 실패한다.

  • 직렬화시 타입 정보드으이 클래스 메타 데이터도 저장하기 때문에 다른 포멧에 비해 용량이 커진다. JSON의 2~10배정도

  • 시스템 규모가 커진다면 캐시 모듈이 기본적으로 직렬화를 제공하기 때문에 다시 점검해야 한다.

  • 외부에 장기간 저장될 데이터는 타입에 엄격한 역직렬화에 대비해 직렬화 사용을 지양해야 한다. 릴리즈 후에는 수정하기 힘들어진다.

  • 직렬화 자체가 클래스의 정보를 저장하기 때문에 외부에 공개될 경우 캡슐화가 깨지게 된다.

마샬링

직렬화는 byte stream으로 변환하는 것이고 마샬링은 변환하는 일련의 과정을 뜻한다. 마샬링이 직렬화보다 더 큰 개념이다. 직렬화는 객체가 대상이지만 마샬링은 변환 자체가 목적이기 때문에 다른 언어간의 전송은 직렬화라고 하지 않고 마샬링이라고 한다.

JSON

JSON(JavaScript Object Notation)은 가벼운 데이터 전송 포멧으로 사람이 읽고 쓰기에 편하다. 1999년 12월에 발표된 ECMA-262 3판의 하위 집합을 기반으로 JSON은 언어에 독립적인 텍스트 형식이다.

자바에서는 주로 Jackson이나 GSON을 이용해 Json과 객체를 변환한다.

출처 우형기술블로그 직렬화vs마샬링 JSON

Last updated