[Java] 자바의 직렬화 (Serialization)

rvlwldev·2023년 2월 18일
0

Java

목록 보기
2/8

직렬화란 사실 자바에서만 사용되는 개념은 아니다.
용어의 설명은 CS에서 객체의 상태를 저장하거나 전송 가능한 형태로 변환하는 프로세스를 의미하는데 대부분의 다른 프로그래밍 언어들과 마찬가지로 자바에서도 중요한 개념 중 하나이다.

또한 자바에서는 java.io.Serializable를 활용한 ByteStream 직렬화만이 직렬화(Serialization) 라고 하며 Marshalling은 JSON, CSV 등 다른 포멧으로 직렬화하는 것 까지 포함하는 더 포괄적인 개념.

(API 서버를 구축할 때 DTO클래스 구현이 생각날 수도 있는데 직렬화와는 다른 개념이다.)


자바 직렬화의 장점

다른 자바시스템에서도 객체를 쉽게 사용할 수 있다.

  • 하나의 서비스를 여러개의 서버로 나누어서 운영한다면, 객체를 직렬화하여 Byte형태로 변환된객체를 각각의 서버끼리 쉽게 주고 받아 사용할 수 있다.

객체를 파일로 저장할 수 있다.

  • 객체를 영구적으로 보관하며 언제든 역직렬화하여 사용할 수 있다.
  • 용량이 큰 객체 라면, 파일로 저장해서 메모리 부족문제를 방지할 수 있다.

객체를 캐싱할 수 있다.

  • 느린 데이터베이스나 네트워크에서 데이터를 매번 로드하는 대신, 한 번 로드한 데이터를 직렬화하여 성능 향상과 네트워크의 부하를 방지하거나 데이터 일관성 유지하는 등의 장점이 있다.

직렬화의 사용방법

ObjectOutputStream을 이용하여 직렬화 할 수 있다.
직렬화 하려는 객체는 java.io.Serializable 인터페이스를 상속해야한다.

ex)

// 직렬화 가능한 클래스
class Person implements Serializable {
    String name;
    int age;
    transient String gender; // transient는 직렬화 대상에서 제외

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

...

Person person = new Person("A", 10);
// 직렬화

// 파일 출력 스트림 생성
FileOutputStream fileOutput = new FileOutputStream("person.ser");
// 객체 출력 스트림 생성
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);

// 객체를 직렬화하여 파일에 쓰기
objectOutput.writeObject(person);

// 객체,파일 출력 스트림 닫기
objectOutput.close();
fileOutput.close();

// 역직렬화

// 파일 입력 스트림 생성
FileInputStream fileInput = new FileInputStream("person.ser");
// 객체 입력 스트림 생성
ObjectInputStream objectInput = new ObjectInputStream(fileInput);

// 파일로부터 직렬화된 객체 읽어오기
deserializedPerson = (Person) objectInput.readObject();

// 객체, 파일입력 스트림 닫기
objectInput.close();
fileInput.close();

// 출력 : A 10
System.out.println(deserializedPerson.name + " " + deserializedPerson.age);

serialVersionUID

참고

Serializable 인터페이스를 상속한다면 serialVersionUID 값을 컴파일러가 클래스의 기본 해쉬값으로 할당한다.

이 값은 클래스의 직렬화 버전을 명시하는 데 사용되며 이 값이 다르다면InvalidClassException 예외를 발생시킨다.

그래서 주로 서버 분산환경에서 데이터의 일관성을 유지하는데 도움을 주지만 변경 내용이 미미하더라도 엄격하게 예외를 발생시키기 때문에 번거로울 수 있다.
(경우에 따라 @SuppressWarnings("serial") 로 무시가 가능하지만 버전관리의 이점을 잃게 된다.)

이 경우 직접 serialVersionUID 값을 할당할 수 있는데 변경내용이 미미한 경우 변경 전과 같은 값을 할당함으로써 예외를 방지할 수 있다.
(멤버 변수 제거 및 이름 변경은 오류는 발생하지 않지만 데이터는 기본적으로 누락됨) 참고

serialVersionUID를 직접 관리하려면 private static final long 으로 선언해야 한다.
역직렬화 시 문제를 방지하기 위해 final이여야 하며 일관성 있게 관리해야 한다.

자바 직렬화의 단점

이식성

  • 자바의 직렬화는 자바에만 종속적이기 때문에 다른 플랫폼으로 이식하는 경우 문제가 발생하기 쉽다. 때문에 JSON 같은 대안을 많이 사용한다.

호환성

  • 위에 말한 serialVersionUID을 직접 관리하지 않고 클래스의 변경이 빈번하게 일어날 경우
    많은 예외가 생길 수 있다. 이 경우 직렬화를 사용하지 않는 편이 좋다.
  • 또한 자바로만, 사용 가능할 때만 역직렬화가 가능하다는 단점이 있다.

용량

  • 자바 직렬화시에 기본적으로 타입에 대한 정보 등 클래스의 메타 정보도 가지고 있기 때문에 상대적으로 다른 포맷에 비해서 용량이 큰 문제가 있다.
    클래스의 구조가 커지면 커질수록 JSON 같은 최소의 메타정보로 직렬화 하는것보다 최소 2배 최대 10배 이상의 용량을 가질 수 있다.

대부분의 단점은 보완할 수 있는 방법이 딱히 없기 때문에 우아한형제들 기술블로그 에서는

1. 외부로 저장되는 데이터는 짧은 만료시간의 데이터를 제외하고 자바 직렬화를 사용을 지양

2. 역직렬화시 반드시 예외가 생긴다는 것을 생각하고 개발

3. 자주 변경되는 비즈니스적인 데이터를 자바 직렬화을 사용X

4. 긴 만료 시간을 가지는 데이터는 JSON 등 다른 포맷을 사용하여 저장

위와 같은 규칙을 말하고 있다.

0개의 댓글