본문 바로가기
java

Serializable

by 킹차니 2021. 11. 21.

자바 Serializable은 아래와 같이 생겼다.

이렇게 텅텅 빈 인터페이스는 왜 사용하는 것인가 궁금하였다. 그리고 직렬화라 함은 CPU와 IO디바이스가 데이터를 주고받을 때와 같은 하나의 시스템이 다른 하나의 시스템과 데이터를 주고 받을 때 직렬화, 역직렬화를 사용한다는 것을 알고 있었지만, 누군가가 물어보면 그것에 대해 자신있게 말할 수 없다. 하여 이 기회를 통해 일반적인 직렬화의 의미를 알아보고, 자바의 Serializable인터페이스에 대해 알아보고자 한다.

 

 

1. 직렬화란?

먼저 위키 백과에는 아래와 같이 나온다.

직렬화(直列化) 또는 시리얼라이제이션(serialization)은 컴퓨터 과학의 데이터 스토리지 문맥에서 데이터 구조나 오브젝트 상태를 동일하거나 다른 컴퓨터 환경에 저장(이를테면 파일이나 메모리 버퍼에서, 또는 네트워크 연결 링크 간 전송)하고 나중에 재구성할 수 있는 포맷으로 변환하는 과정이다.[1]

오브젝트를 직렬화하는 과정은 오브젝트를 마샬링한다고도 한다.[2] 반대로, 일련의 바이트로부터 데이터 구조를 추출하는 일은 역직렬화 또는 디시리얼라이제이션(deserialization)이라고 한다.             
               
-위키백과

즉 어떤 데이터가 어떤 시스템 A에 의해 저장이 되었다면 해당 데이터는 그 어떤 시스템 A에 의한 포맷으로 저장되었을 것이다. 하지만 이는 다른 어떤 시스템 B와는 포맷이 다를 것이다. 하여 시스템 A에 저장된 데이터를 시스템 B로 보내기 위해서는 서로 다른 포맷을 맞춰주어야한다. 이때 직렬화를 사용하는 것이다. 데이터를 직렬화하여 바이트 구조의 데이터로 만들어 시스템 B에게 보낸다면 B는 요 바이트 데이터를 역직렬화 하여 자신의 포맷에 맞추어 받는 것이다.

 

이는 오늘과 같은 분산 시스템 환경에서 기본이 되는 기술이다.

 

 

 

2. 자바의 Serializable 알아보기

 

위에서 알아본 바에 의하면 자바의 직렬화도 같은 기능을 한다고 알 수 있다. 참고한 블로그에서는 자바의 직렬화에 대해 아래와 같이 말하고 있다.

 

📍 자바 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데       이터 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기합니다.

 

📍시스템적으로 이야기하자면 JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트        형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 이야기한다.

 

아래와 같은 상황에서 자바 직렬화가 필요할 것이다.

 

1. 생성한 객체를 파일로 저장한다.

2. 저장한 객체를 읽을(read) 일이 있다. 

3. 다른 서버에 생성한 객체를 받아야 한다.

 

위와 같은 상황에서 Serializable 인터페이스를 구현한다면 직렬화를 통해 데이터를 주고 받고, 저장하고, 읽을 수 있다.

즉, Serializable 인터페이스를 구현하면 JVM에서 해당 객체는 저장하거나 다른 서버로 전송할 수 있게 해준다. 

 

 

 

serialVersionUID와 Transient

자바의 HashMap 클래스 : 

위의 HashMap을 보면 Serializable을 구현한 것을 볼 수 있다. 그리고 아래에 serialVersionUID를 가지고 있다. 만약 Serializable인터페이스를 구현하여 사용한다면 serialVersionUID를 지정해주는 것을 권장한다. 자바 시스템간에 통신하기 위해서는 요 UID로 같은 객체임을 안다.

예로 A서버에서 B서버로 Book객체를 전송한다면 A서버에도 Book객체가 있어야하고, B서버에도 Book객체가 있어야한다. 그래서 A가 Book객체를 B로 보낼 때, B가 제대로 받고 이를 역직렬화 할 수 있을 것이다. 그런데 만약 A에서의 Book클래스의 UID와 B에서의 Book클래스의 UID가 다르다면 이들이 같은 것인지 모르고 제대로 인식하지 못한다. 또한 UID는 같은데 A의 Book클래스와 B의 Book클래스가 필드가 다르면 이 또한 같은 클래스인지 인식하지 못하여 전송에 실패한다. 하여 UID는 반드시 같게 해주고, A의 Book클래스에 따로 추가할 필드가 있다면 transient를 붙여준다. 이는 JPA에서도 사용되는데, 이를 붙여주면 따로 해당 필드는 무시한다.

 

transient pricate int bookPrice;

(transient를 필드에 붙인 예시)

 

 

직렬화는 또 어디서 사용되나?

JSON, XML, CSV도 모두 직렬화의 한다기 방법이다. 또한 프로토콜 버퍼에서 제공하는 .proto파일을 프로토콜 버퍼 컴파일러를 사용하여 컴파일하면 .proto에서 정의한 message들이 직렬화되어 (만약 자바 형태로 컴파일한다면) 자바 객체로 변환된다.

 

 

위와 같은 많은 직렬화 기술이 있는데, 자바 직렬화를 왜 굳이 사용하지?

자바 직렬화는 자바 베이스 시스템간의 통신을 위해 사용한다. 또한 아래와 같은 장점이 있다.

자바 직렬화의 장점:
1. 자바 직렬화는 자바 시스템에서 개발에 최적화되어 있다.
2. 복잡한 데이터 구조의 클래스의 객체라도 직렬화 기본 조건만 지키면 큰 작업 없이 바로 직렬화를 가능합니다. 물론 역직렬화도 마찬가지.

3. 당연하게 보이는 장점 중에 하나지만 데이터 타입이 자동으로 맞춰지기 때문에 관련 부분을 큰 신경을 쓰지 않아도 됩니다.
   그렇게 역직렬화가 되면 기존 객체처럼 바로 사용할 수 있게 됩니다. 개발자 입장에서 상당히 편한 부분.

 

 

자바 직렬화는 언제 어디서 사용되나?

JVM의 메모리에서만 상주되어있는 객체 데이터를 그대로 영속화(Persistence)가 필요할 때 사용됩니다.
시스템이 종료되더라도 없어지지 않는 장점을 가지며 영속화된 데이터이기 때문에 네트워크로 전송도 가능합니다.
그리고 필요할 때 직렬화된 객체 데이터를 가져와서 역직렬 화하여 객체를 바로 사용할 수 있게 됩니다.
그런 특성을 살린 자바 직렬화는 많은 곳에서 이용됩니다. 많이 사용하는 부분 몇 개만 이야기해보겠습니다.

  • 서블릿 세션 (Servlet Session)
    서블릿 기반의 WAS(톰캣, 웹로직 등)들은 대부분 세션의 자바 직렬화를 지원하고 있습니다.
    물론 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만,
    파일로 저장하거나 세션 클러스터링, DB를 저장하는 옵션 등을 선택하게 되면 세션 자체가 직렬화가 되어 저장되어 전달됩니다.
    (그래서 세션에 필요한 객체는 java.io.Serializable 인터페이스를 구현(implements) 해두는 것을 추천합니다.)
    참고로 위 내용은 서블릿 스펙에서는 직접 기술한 내용이 아니기 때문에 구현한 WAS 마다 동작은 달라질 수 있습니다.
  • 캐시 (Cache)
    자바 시스템에서 퍼포먼스를 위해 캐시(Ehcache, Redis, Memcached, …) 라이브러리를 시스템을 많이 이용하게 됩니다. 자바 시스템을 개발하다 보면 상당수의 클래스가 만들어지게 됩니다. 예를 들면 DB를 조회한 후 가져온 데이터 객체 같은 경우 실시간 형태로 요구하는 데이터가 아니라면 메모리, 외부 저장소, 파일 등을 저장소를 이용해서 데이터 객체를 저장한 후 동일한 요청이 오면 DB를 다시 요청하는 것이 아니라 저장된 객체를 찾아서 응답하게 하는 형태를 보통 캐시를 사용한다고 합니다.
    캐시를 이용하면 DB에 대한 리소스를 절약할 수 있기 때문에 많은 시스템에서 자주 활용됩니다. (사실 이렇게 간단하진 않습니다만 간단하게 설명했습니다.)
    이렇게 캐시 할 부분을 자바 직렬화된 데이터를 저장해서 사용됩니다. 물론 자바 직렬 화만 이용해서만 캐시를 저장하지 않지만 가장 간편하기 때문에 많이 사용됩니다.
  • 자바 RMI(Remote Method Invocation)
    최근에는 많이 사용되지 않지만 자바 직렬화를 설명할 때는 빠지지 않고 이야기되는 기술이기 때문에 언급만 하고 넘어가려고 합니다.
    자바 RMI를 간단하게 이야기하자면 원격 시스템 간의 메시지 교환을 위해서 사용하는 자바에서 지원하는 기술입니다.
    보통은 원격의 시스템과의 통신을 위해서 IP와 포트를 이용해서 소켓통신을 해야 하지만 RMI는 그 부분을 추상화하여 원격에 있는 시스템의 메서드를 로컬 시스템의 메서드인 것처럼 호출할 수 있습니다.
    원격의 시스템의 메서드를 호출 시에 전달하는 메시지(보통 객체)를 자동으로 직렬화 시켜 사용됩니다.
    그리고 전달받은 원격 시스템에서는 메시지를 역직렬화를 통해 변환하여 사용됩니다.

 

위의 글 대부분이 거의 아래 두개의 글을 옮겨다 놓은 것이다.

 

참고 블로그:

1. https://devlog-wjdrbs96.tistory.com/268

2. https://techblog.woowahan.com/2550/

'java' 카테고리의 다른 글

Lambda 02 - java.util.function 패키지  (0) 2021.12.23
Lambda 01  (0) 2021.12.23
인터페이스 - 느슨한 결합력  (0) 2021.04.25
자바의 다형성  (0) 2021.03.25
Java - 4강 추상 클래스, 템플릿 메서드, final예약어  (0) 2021.02.21