1. 자바 직렬화란?
자바에서 직렬화(Serialization)는 객체(Object)의 상태를 바이트 스트림(Byte Stream)으로 변환하는 기술을 말한다.
반대로 역직렬화는(Deserialization)는 바이트 스트림을 다시 원래의 객체로 변환하는 과정이다.
2. 왜 직렬화가 필요할까?
자바 객체(Object)는 기본적으로 JVM에 저장되기 때문에 프로그램이 종료되면 사라지게 된다.
이를 DB에 저장하는 것과 같이, 다른 시스템에 전송하기 위해 전송 규격에 맞는 바이트로의 직렬화가 필요하게 되는 것이다.
1) 데이터 영속화
: 객체를 파일, 데이터베이스 등에 저장
2) 네트워크 전송
: Http 요청, 소켓 프로그래밍, RMI(Remote Method Invocation) 등을 통해 객체 전송
3) 캐시 저장
: 객체를 빠르게 조회하기 위해 캐시 저장
3. 직렬화 방법에는 무엇이 있을까?
1) interface Serializable
Java 표준 라이브러리에서 제공하는 `java.io.Serializable` 인터페이스를 구현하여 객체를 직렬화를 하는 방식이다.
`Serializable`은 선언되어 있는 메서드가 없는 마커 인터페이스로, 직렬화 가능 객체라고 단순히 그 개념을 알려주는 역할에 그친다.
public interface Serializable {
}
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 직렬화 버전 관리
private String name;
private int age;
Object obj; // Serializable 구현 x
}
주요 개념
1. 비직렬화 부모 클래스가 있으면, 부모 필드는 직렬화되지 않으며 해당 부모 클래스의 기본 생성자가 호출 및 초기화 된다.
2. 직렬화 과정에서 직렬화되지 않는 객체가 포함되면 NotSerializableException이 발생한다.
→ transient 키워드를 사용해 직렬화 대상에서 제외한다.
3. serialVersionUID를 명시적으로 선언하여, 버전 충돌을 방지한다.
4. enum 및 record 클래스는 별도의 직렬화 방식을 적용한다.
- enum
- Enum 클래스가 Serializable을 이미 구현함
- 단, 인스턴스 필드는 직렬화되지 않고 상수 이름(name) 기준으로 직렬화와 역직렬화가 된다.
- record
- Serializable 구현 시 모든 컴포넌트가 직렬화된다.
- 역직렬화 시 정식 생성자(canonical constructor) 가 호출된다. 따라서 생성자에 넣은 유효성 검사 로직이 역직렬화 할 때도 실행된다.
cf. 일반 클래스는 역직렬화 시, `ObjectInputStream`이 내부적으로 `sun.misc.Unsafe.allocateInstance()`를 사용해 메모리를 직접 할당하고, 바이트 스트림에서 얻은 값을 리플렉션으로 직접 주입한다.
serialVersionUID
: 직렬화 버전 관리를 위한 변수로, 직렬화 된 객체를 올바르게 역직렬화를 하기 위해서는 serialVersionUID 가 일치해야 한다.
serialVersionUID가 일치하지 않으면 InvalidClassException 이 발생한다.
따라서 직렬화 가능한 클래스는 명시적으로 serialVersionUID를 선언하는 것을 권장한다.
Q. serialVersionUID 정의를 안하면 어떻게 될까?
`serialVersionUID`를 정의하지 않으면 JVM이 해당 클래스의 메타데이터를 기반으로 자동으로 생성한다.
따라서 클래스 구조가 바뀌면 `serialVersionUID`도 함께 바뀌게 되어, 이전 버전에서 저장한 데이터를 역직렬화를 시도InvalidClassException 예외가 발생하게 되므로, 직렬화가 필요한 경우 명시적으로 선언하도록 하자!
cf. 클래스 메타데이터: 클래스 이름 / 필드 / 메서드 / 접근 제한자 / 구현한 인터페이스 목록
Q. QueryDSL QClass에 serialVersionUID가 정의되어 있다?
QueryDSL을 사용하다보면 QClass가 자동으로 생성되고, 이를 기반으로 타입 안전성을 확보한 쿼리를 작성할 수 있다.
그런데 우연히 QClass에서 `serialVersionUId`가 정의되었음을 볼 수 있었다.
상위 부모를 타고 올라가보니 QEntity > EntityPathBase > EntityPath > Path > Expression 에서 `Serializable`을 구현하고 있어었다. 따라서 하위 클래스인 QClass도 직렬화가 가능해져, 자동으로 `serialVersionUId`가 정의된 듯하다.
하지만 곰곰히 생각해보면 QClass는 타입 안전하게 쿼리를 작성하기 위함이지, 실제로 QClass 자체를 직렬화 한 스트림을 보낼 일은 없다.
(실질적인 의미는 없는 정의라고 봐도 무방할 것 같다..!)


2) Json 직렬화
웹 개발을 하다보면 클라이언트와 서버가 데이터를 주고받을 때, 많이 사용하는 양식이 JSON이다.
이 때, 자바 객체를 JSON으로 변환하는 직렬화와 JSON을 자바 객체로 변환하는 역직렬화 과정이 수행된다.
/** Jackson 라이브러리 **/
// 1. Person 객체 생성
Person person = new Person("홍길동", 20);
// 2. ObjectMapper 생성
ObjectMapper objectMapper = new ObjectMapper();
// 3. JSON으로 직렬화
String jsonString = objectMapper.writeValueAsString(person);
스프링에서는 기본적으로 Jackson 라이브러리를 사용하여 요청/응답을 직렬화/역직렬화 한다.
아래 예시에서 내부적으로 @RequestBody 요청에서 역직렬화가, ResponseEntity 응답에서 직렬화가 수행된다.
(HttpMessageConverter > MappingJackson2HttpMessageConverter > ObjectMapper)
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping
@ApiOperation(value = "공장 등록")
public ResponseEntity<SaveUserResponse> saveUser (
@RequestBody SaveFactoryForm saveUserRequest
) {
return ResponseEntity.ok(-)
}
}
4. 왜 JSON 직렬화가 아닌 자바 직렬화를 사용하지?
1) 자바 직렬화의 장점
∙ 자바 시스템 최적화
자바 직렬화는 자바 시스템에 최적화 되어, JVM 내부에서 직렬화와 역직렬화가 쉽게 가능하도록 설계되어 있다.
즉, 같은 자바 환경의 애플리케이션에서는 직렬화 된 객체를 그대로 사용이 가능해 빠르게 처리가 가능하다.
∙ 완벽한 객체 상태 보존
자바에서의 객체 간의 참조 관계인 객체 그래프와 객체의 클래스 정보와 같이 객체를 그대로 유지하며 직렬화가 가능하다.
JSON 직렬화는 이러한 객체 참조와 타입 정보를 포함하지 않기 때문에, 복잡한 객체 구조에서는 자바 직렬화가 유리하다.
2) 자바 직렬화의 단점
∙ 다른 시스템 간의 호환성
자바 직렬화는 JVM에서만 동작하기 때문에, 파이썬이나 JS와 같은 다른 언어와 데이터를 주고받을 때는 JSON을 사용해야 한다.
∙ 가독성
바이너리 형식으로 직렬화가 되어, 개발자가 직접 읽으며 디버깅이 불가능하다.
5. 그럼 자바 직렬화가 사용되는 상황은?
1) 서블릿 세션
서블릿 기반의 WAS에서 세션은 기본적으로 JVM 메모리에서 관리하고 있다. 단순히 세션을 JVM 메모리 위에서 사용한다면, 객체는 생성된 형태 그대로 존재하므로 별도의 직렬화 없이 객체를 바로 사용할 수 있다.
하지만 객체를 '전송'하거나 '저장'과 같이 JVM 외부로 객체를 내보내야 할 때 직렬화 과정이 필요하다.
세션 클러스터링
: 여러 WAS 서버가 세션 정보를 공유하여 동일한 세션 정보를 유지하게 함
방법
- Sticky Session
- Session Replication
- 외부 세션 저장소 활용 (with. redis)
- 여기에서 redis에 세션 객체를 저장할 때 직렬화가 필요하다!
- 참고로 직렬화 방법(자바, JSON, String)은 다양하다!! (반드시 자바 직렬화를 사용해야 하는 건 아니다..)
2) 캐시 (Redis, Ehcache..)
캐시에서는 데이터를 빠르게 저장하고 조회할 수 있어야 한다.
자바 직렬화는 바이트 스트림으로 변환되므로 텍스트 포맷인 JSON보다 더 작은 공간을 사용하며 저장할 수 있다.
캐시 시스템에 데이터 가독성과 유연한 관리를 위해 JSON 직렬화 또한 많이 사용되고 있다.
cf. 참고로 자바 애플리케이션과 DB 간의 통신에서는 JDBC 프로토콜 형식으로 데이터를 주고 받는다.
참고
1) 자바 직렬화의 전반적인 내용 파악 / 자바 직렬화 문제점
2) 왜 자바 직렬화를 사용할까?
'TIL' 카테고리의 다른 글
| AWS AIF 후기 (0) | 2026.03.02 |
|---|---|
| 블로그 글쓰기의 '이미지 업로드'는 어떻게 동작할까?? (0) | 2025.12.17 |
| Python 코드 난독화 (0) | 2025.09.24 |
| jar 파일 실행해 보셨어요? (1) | 2025.05.25 |
| MCP 에 대해 알아보자 (0) | 2025.05.21 |