자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술
즉, 직렬화란 현재 데이터(structure, object)의 상태를 영속적으로 저장하거나 다른 환경으로 전달(네트워크 통신 등)하기 위해 어떠한 정해진 포맷으로 변환하는 과정
각자 PC의 OS마다 서로 다른 가상 메모리 주소 공간을 갖기 때문에, Reference Type의 데이터들은 인스턴스를 전달 할 수 없다.
따라서, 이런 문제를 해결하기 위해선 주소값이 아닌 Byte 형태로 직렬화된 객체 데이터를 전달해야 한다.
직렬화된 데이터들은 모두 Primitive Type(기본형)이 되고, 이는 파일 저장이나 네트워크 전송 시 파싱이 가능한 유의미한 데이터가 된다. 따라서, 전송 및 저장이 가능한 데이터로 만들어주는 것이 바로 '직렬화(Serialization)'이라고 말할 수 있다.
자바에서는 간단히 java.io.Serializable
인터페이스 구현으로 직렬화/역직렬화가 가능하다.
역직렬화는 직렬화된 데이터를 받는쪽에서 다시 객체 데이터로 변환하기 위한 작업을 말한다.
직렬화 대상 : 인터페이스 상속 받은 객체, Primitive 타입의 데이터
Primitive 타입이 아닌 Reference 타입처럼 주소값을 지닌 객체들은 바이트로 변환하기 위해 Serializable 인터페이스를 구현해야 한다.
package java.io;
public interface Serializable {}
@Entity
@AllArgsConstructor
@toString
public class Post implements Serializable {
private static final long serialVersionUID = 1L;
private String title;
private String content;
serialVersionUID
를 만들어준다.
Post post = new Post("제목", "내용");
byte[] serializedPost;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(post);
serializedPost = baos.toByteArray();
}
}
//결과 예시
serializedUserBase64 >> rO0ABXNyABduZXQuaGFwcHlrb28ubW9kZWwuVXNlcqLhsk0TYPUEAgADSQADYWdlTAAFZW1haWx0ABJMamF2YS9sYW5nL1N0cmluZztMAARuYW1lcQB+AAF4cAAAAB50ABRydWRhbHM0NTQ5QGdtYWlsLmNvbXQACEhhcHB5a29
ObjectOutputStream
으로 직렬화를 진행한다. Byte로 변환된 값을 저장하면 된다.
try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedPost)) {
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
Object objectPost = ois.readObject();
Post post = (Post) objectPost;
}
}
//결과 예시
Post title: 제목, content: 내용
ObjectInputStream
로 역직렬화를 진행한다. Byte의 값을 다시 객체로 저장하는 과정이다.
위의 코드에서 serialVersionUID
를 직접 설정했었다. 사실 선언하지 않아도, 자동으로 해시값이 할당된다.
직접 설정한 이유는 기존의 클래스 멤버 변수가 변경되면 serialVersionUID
가 달라지는데, 역직렬화 시 달라진 넘버로 Exception이 발생될 수 있다.
따라서 직접 serialVersionUID
을 관리해야 클래스의 변수가 변경되어도 직렬화에 문제가 발생하지 않게 된다.
serialVersionUID
을 관리하더라도, 멤버 변수의 타입이 다르거나, 제거 혹은 변수명을 바꾸게 되면 Exception은 발생하지 않지만 데이터가 누락될 수 있다.
serialVersionUID는 자바의 직렬화에서 객체의 버전 관리를 위해 사용되는 필드입니다.
주요 포인트는:
Serializable 인터페이스를 구현하는 클래스에서는 serialVersionUID 값을 명시적으로 지정하는 것이 바람직합니다.
데이터를 통신 상에서 전송 및 저장하기 위해 직렬화/역직렬화를 사용한다.
serialVersionUID
는 개발자가 직접 관리한다.
클래스 변경을 개발자가 예측할 수 없을 때는 직렬화 사용을 지양한다.
개발자가 직접 컨트롤 할 수 없는 클래스(라이브러리 등)는 직렬화 사용을 지양한다.
자주 변경되는 클래스는 직렬화 사용을 지양한다.
역직렬화에 실패하는 상황에 대한 예외처리는 필수로 구현한다.
직렬화 데이터는 타입, 클래스 메타정보를 포함하므로 사이즈가 크다. 트래픽에 따라 비용 증가 문제가 발생할 수 있기 때문에 JSON 포맷으로 변경하는 것이 좋다.
JSON 포맷이 직렬화 데이터 포맷보다 2~10배 더 효율적