직렬화와 역직렬화에 대해서 대부분은 알고 있습니다. 하지만 왜 사용해야하며 어떤 상황에는 쓰지 않아도 되는지는 잘 모릅니다. 제 참신한 궁금증으로 한번 설명해보겠습니다.
직렬화 / 역직렬화란 (Serializable / Deserializable)
먼저 컴퓨터 공학에서 말하는 직렬화 / 역직렬화에 대해서 알아보겠습니다.
직렬화 - 디스크에 저장, 네트워크 통신에 사용하기 위한 형식을 변환하는것
역직렬화 - 디스크에 저장한 데이터를 읽거나 네트워크 통신으로 받은 데이터 메모리에 쓸 수 있도록 변환하는것
일종의 인코딩, 디코딩 같은 느낌인데 왜 우리는 형식을 변환시켜야 하는걸까요?
데이터 들의 메모리 구조는 크게 value type(스택에 쌓임), reference type(힙에 메모리 할당, 스택은 힙 주소)로 나뉩니다. 그런데 디스크에 저장하거나 통신하는데에는 value type만으로 가능합니다. 주소값만으로는 휘발성인 메모리에서 값을 지속적으로 가져올 수가 없기 때문입니다. 누군가의 집주소가 영구적이지 않은것 처럼.
"자바" 직렬화는 어디에 사용되는가
- 서블릿 세션
- 분산 구조 서버에서 세션 데이터를 공유해야 할때
- 톰캣의 세션
- 캐시
- DB에서 조회한 객체 데이터가 다른 모듈에서 필요할때
- 직렬화가 꼭 필요하진 않지만 자바에서 구현이 간편
간단히 말해서 JVM 메모리에서만 상주되어있는 객체 데이터를 영속화 할때 사용됩니다. 이런 영속화는 시스템이 종료되더라도 없어지지 않습니다.
그럼 분산이 아닌 단일 구조 서버에서, 세션이 아닌 JWT 토큰 인증 방식을 사용한다면 Serializable은 필요없는가?
저장, 통신 기능이 없는 경우 그렇다고 한다.
하지만 내 기억상으론 spring 서버에서 entity에 serializable을 구현한 형태를 많이 봤던것 같다... 그것들은 무엇을 위한 거였지?
없어도 되는게 맞지만 JPA 표준 스펙은 Entity에 Serializable을 구현하도록 되어있다고 합니다. 앞에서 말한 기능의 가능성을 열어두려는 의도인데 실무에서 entity에 serializable은 거의 사용하지 않는다고 합니다. 특히 JSON의 경우 jackson이 객체를 json으로 알아서 변환하고 역직렬화 해주기 떄문입니다.
Jackson은 무엇이고 어떻게 동작하는가
어떤 데이터를 표현하는 방식은 너무나도 다양합니다. 그야말로 정답이 없는 문제입니다. 하지만 여러 컴퓨터들과 일관된 통신을 하기 위해선 어떤 통일된 데이터 표현이 필요합니다. 우리가 영어를 국제공통어로 쓰는것 처럼요. 이를 위해 고안된것이 대표적으로 XML이나 JSON가 있습니다. 특히나 웹 API 통신에서 JSON이 가장 많이 사용되고 있습니다.
앞서 말했듯 코드상의 어떤 데이터(자바에서 객체)는 Primitive한 형태가 아닙니다. 결국 데이터를 원하는 JSON으로 변환시켜야하는데 Jackson은 annotaion만을 사용하면 ObjectMapper API를 사용하여 알아서 변환시켜줍니다.
Jackson이 동작하기 위한 여러 조건이 존재합니다.
- getter와 setter가 있을경우 필드이름을 유추하여(get, set을 제거하고 첫문자를 소문자로 치환한 이름) objectMapper를 사용하여 직렬화함
- getter는 직렬화/역직렬화 모두 가능하게 하지만 setter는 역직렬화만 가능
- setter, 생성자는 접근제한자 제한 x, 나머지는 public
여러가지가 존재하는데 더 자세한 사용법은 Reference를 참고해주세요.
그런데 Serializable를 쓰지말라고?
직렬화에서 딴길로 새서 Jackson까지 갔지만 다시 돌아와봅시다. 직렬화를 해야하는 근거는 지금까지 너무 충분하고 일리가 있습니다. 하지만 아이러니하게도 직렬화는 권장하지 않는 방법입니다. 그 이유를 알아보겠습니다.
- 직렬화는 용량이 크다
직렬화는 객체의 타입, 메타 정보 등을 추가적으로 가지므로 용량이 2배 이상 차이납니다. 따라서 DB, Cache에 저장할때 지양해야합니다. - 보안 위험성
역직렬화 과정에서 공격자의 악성 코드가 수행될 수 있습니다. - 배포후 수정이 어렵다
직렬화된 바이트 스트림 인코딩도 하나의 공개 API가 되는것이기 때문에 직렬화 형태가 고정이 됩니다. 앞으로의 유지보수가 직렬화에 묶이게 됩니다. - 클래스 캡슐화가 깨진다
직렬화 형태가 하나의 공개 API가 되어 캡슐화가 깨지게 됩니다. - 상속용 클래스와 인터페이스에 직렬화 구현에 주의
상속용 클래스에 Serializable을 구현하는것은 하위 클래스에 문제를 그대로 전달하는것과 같습니다. 인스턴스 필드의 값중에 불변식을 보장할게 있다면 finalize 메서드를 재정의하지 못하게 해야합니다. - 내부 클래스는 직렬화 구현 x
내부 클래스의 직렬화 형태는 불분명하기 때문에 Serializable을 구현하면 안됩니다. 단 static 내부 클래스는 괜찮습니다.
# Reference
https://velog.io/@jinyeong-afk/Springboot-Entity에-Serializable-구현을-해야-하나
https://www.inflearn.com/questions/17117/serializable-질문-드립니다
'Back-end' 카테고리의 다른 글
[Effective Java] 1. 객체 생성과 파괴 (2) | 2024.06.03 |
---|---|
Github actions pull_request_target (0) | 2024.01.10 |
[JVM 동작원리] 3. Execution engine (0) | 2023.10.16 |
[JVM 동작원리] 2. Runtime Data Area (0) | 2023.10.12 |
[JVM의 동작원리] 1. 클래스 로더 (0) | 2023.10.10 |