[REST API] Serializable 정말 구현해야 할까?
개발 완료 후 시간이 좀 남아돌아 다른사람들 소스를 보다보니
DTO에 죄다 Serializable 을 implement 해놨음..
엇? 외부로 직렬화해서 내보내는건가? 싶어 확인해보다 내가 개념 정리하려고 쓰는 포스팅.
직렬화란?(Serializable)
자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기한다.
시스템적으로 이야기하자면 JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 이야기한다.
직렬화는 java.io 패키지의 Serializable 인터페이스를 implements하면 가능하다.
* 단 직렬화 대상은 필드(멤버변수)들이다. 생성자와 메서드는 대상에 포함되지 않는다.
서버가 다중화(여러개 존재) 되어 있고 세션 클러스터링을 통해 세션 관리를 하는 환경에서 도메인 객체가 세션에 저장될 때, 도메인 객체가 세션에 저장될 때,
도메인 객체에 Serializable 인터페이스 클래스를 구현해야지 정상적으로 세션을 저장하고 꺼내올 수 있다.
도메인 객체가 세션에 저장하지 않는 단순한 데이터의 집합이고 컨트롤러에서 생성되어 뷰에서 소멸하는 데이터의 전달체라면 객체 직렬화는 고려하지 않아도 되는 부분이다.
근데 쓰이지 않는데 구현하는게 과연 좋은걸까?
대답은 NO
▪ Serializable 을 구현하면 릴리즈 이후에 수정이 어렵다(여기서 릴리즈는 서버 릴리즈가 아님)
▪ Serializable 을 구현하면 byte stream encoding 도 하나의 공개 API 가 된다.
즉, private, package-private 인스턴스 필드들도 API 로 공개하는 꼴이 된다. (캡슐화 깨짐)
▪ 시간이 지나 내부 구현을 수정하게 되면 원래의 직렬화 형태와 달라지게 된다.(그래서 영원히 관리해야 하는 대상이 된다.)
▪ 직렬화를 구현하고자 한다면 감당할 수 있을 만큼의 고품질의 직렬화 형태로 설계해야 한다.(대충 매우 신경써야한단소리)
그럼 언제쓰느냐?
- JVM 메모리에서만 상주되어 있는 객체 데이터를 그대로 영속화가 필요할 때 사용
- 시스템이 종료되더라도 없어지지 않는 장점을 가지며 영속화된 데이터이기 때문에 네트워크로 전송도 가능
- 필요할 때 직렬화된 객체 데이터를 가져와서 역직렬화하여 객체를 바로 사용할 수 있게 된다.
1) 서블릿 세션(Servlet Session)
- 서블릿 기반의 WAS(톰캣, 웹로직 등)들은 대부분 세션의 자바 직렬화를 지원
- 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않음
- 하지만 파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달
- 세션에 필요한 객체는 java.io.Serializable 인터페이스를 구현(implements) 해두는 것을 추천
2) 캐시 (Cache)
자바 시스템에서 퍼포먼스를 위해 캐시(Ehcache, Redis, Memcached, …)라이브러리를 시스템을 많이 이용하게 된다.
자바 시스템을 개발하다 보면 상당수의 클래스가 만들어지게 된다.
예를 들면 DB를 조회한 후 가져온 데이터 객체 같은 경우 실시간 형태로 요구하는 데이터가 아니라면 메모리, 외부 저장소, 파일 등을 저장소를 이용해서 데이터 객체를 저장한 후 동일한 요청이 오면 DB를 다시 요청하는 것이 아니라 저장된 객체를 찾아서 응답하게 하는 형태를 보통 캐시를 사용한다.
캐시를 이용하면 DB에 대한 리소스를 절약할 수 있기 때문에 많은 시스템에서 자주 활용된다.
이렇게 캐시 할 부분을 자바 직렬화된 데이터를 저장해서 사용 물론 자바 직렬화만 이용해서만 캐시를 저장하지 않지만 가장 간편하기 때문에 많이 사용된다.
역직렬화 조건
- 직렬화 대상이 된 객체의 클래스가 클래스 패스에 존재해야 하며 import 되어 있어야 한다
- 중요한 점은 직렬화와 역직렬화를 진행하는 시스템이 서로 다를 수 있다는 것을 반드시 고려해야 한다
- 자바 직렬화 대상 객체는 동일한 serialVersionUID 를 가지고 있어야 한다.
직렬화: 데이터를 Stream 으로 전송할 수 있는 상태로 만든다 (ex. 파일)
역직렬화: Stream 으로 전송 받은 데이터를 객체로 만든다
직렬화 방법
- CSV, JSON, 프로토콜 버퍼 등은 시스템의 고유 특성과 상관없는 대부분의 시스템에서의 데이터 교환 시 많이 사용된다
- 자바 직렬화 형태의 데이터 교환은 자바 시스템 간의 데이터 교환을 위해서 존재한다.목적에 따라 적절하게 사용하자!
자바 직렬화의 장점
- 자바 직렬화는 자바 시스템에서 개발에 최적화
- 복잡한 데이터 구조의 클래스의 객체라도 직렬화 기본 조건만 지키면 큰 작업 없이 바로 직렬화를 가능(역직렬화도)
- 데이터 타입이 자동으로 맞춰지기 때문에 관련 부분을 큰 신경을 쓰지 않아도 된다
- 그렇게 역직렬화가 되면 기존 객체처럼 바로 사용 가능
결론
-> Serializable 구현 여부는 가볍게 결정할 사안이 아니다.
Serializable 을 구현에 따른 비용이 적지 않으니 그 이득과 비용을 잘 저울질 해야한다
(단, 객체를 전송하거나, 직렬화를 이용한 framework 에서는 선택의 여지가 없음)
참조 :
https://blog.yevgnenll.me/posts/implement-serializable-with-great-caution-effective-java-86