[Java] 직렬화(Serializable) 이해하기

들어가며


가끔 JDK API 에 내부 구현이 궁금해 내부 구현을 파고들다 보면 몇몇의 상위 객체는

implements Serializable 을 구현 하고 있는 것을 본적이 있을 것 입니다.

 

평소에는 그냥 이런게 있구나 하고 가볍게 넘기곤했다.

그러다 JPA 관련 문서를 보다가, JPA 공식 문서에 Entity 의 기본 구현은 Serializable 을 구현하는 것이라는 것을 봤다.

 

하지만 저는 Entity 를 구성하면서 한번도 Serializable  을 구현한적이 없었죠.

 

그래서 궁금했습니다. 이게 뭐길래 다양한 객체 내부구현을 타고가다 보면 최상위에 있는지 왜? 이걸 구현하는지가 궁금했다.

 

그래서 한번 공부를 해봤다.

 

1. 직렬화, 역직렬화


직렬화는 간단하게 설명해 객체를 외부의 자바 시스템에서도 사용할 수 있도록 바이트 스트림으로 형태로 변환하는 것이다.

 

역직렬화는 바이트 스트림 을 다시 객체로 변환하는 것이다.

 

📌 Tip

모든 네트워크 전송은 바이트 형태로 전달이 된다. 

 

 

OSI 7계층을 봐보자

https://medium.com/@sreekanth.thummala/osi-model-7-layers-dataflow-example-b711dbca5eff

 

예를들어 클라이언트에서 네트워크 요청(Ex) http 요청)이 들어오면 최상위 계층인 응용 계층에서 전달 받아 

그 데이터를 컴퓨터(os) 가 이해할 수 있는 데이터로 가공을 하여 최하위 계층인 물리 계층으로 전달이 된다.

 

물리 계층으로 전달된 데이터가 이제 서버로 전달이 될 것 입니다.

그리고 서버에서 요청받은 값을 다시 클라이언트에게 응답을 해줘야 합니다.

 

이번엔 반대로 물리계층 에서 부터 응용계층 까지

(컴퓨터가 읽을 수 있는 언어 -> 사람이 읽을 수 있는 언어) 로 변환이 되어 최종적으로 저희가 보고 읽을 수 있게 전달이 됩니다.

 

위 내용을 보고 다시 직렬화, 역직렬화를 보면 이해가 더 잘 갈 수 있습니다.

 

1-1) 직렬화

직렬화/역직렬화 프로세스는 독립적으로 실행되어야 한다.

즉, A 자바 시스템에서 직렬화한 내용은 다른 B 자바 시스템에서 역직렬화할 수 있어야 한다.

 

자바 직렬화는 이를 지원하며, 대신 직렬화/역직렬화 대상 클래스에 Serializable 인터페이스를 꼭 구현해야 한다.

 

아래는 객체를 직렬화 시키는 방법이다

 

위 메소드는 ObjectOutput 인터페이스 안에 메소드 이다.

그리고 그 구현체는 ObejctOutputStream 클래스 이다.

 

위 메소드를 보고 의아할 수도 있다.

객체를 직렬화 시키면 return 타입은 직렬화될 타입인 바이트 스트림? 이어야 하는것 아닌가????

 

위 내용을 이해하는데 필자는 시간이 좀 많이 들었다..

 

 

위 hierarchy 를 보면 이해가 조금이라도 될 수도 있다. 

 

ObjectOutputStream 을 writeObject() 메소드를 사용하는데 ObjectOutputStream 은

java.io.OutputStream 을 상속받으므로, 해당 객체 생성시 OutputStream 을 주입받는다.

 

즉 writeObject() 를 실행하면 주입받은 OutputStream 에 직렬화된 바이트 스트림 데이터를 write 한다. 

(write -> 메모리에 있는 데이터들을 전송하는 것)

 

실제 writeObject 구현체이다.

 

직렬화는 내부에 데이터가 외부로 나가게 되는 것이 므로 (output) 과 관련있음을 알아야 한다.

 

 

1-2) 역직렬화

역직렬화는 반대로 바이트 스트림 -> 객체 로 만드는 것이다. 

즉 외부에 것을 내부 데이터로 만드는 것이므로 (Input) 과 관련이 있다.

 

 

위 readObject() 는 역질렬화 하는 메소드 이다. 

직렬화는 리턴타입이 void 였는데 이번에는 Object 이다.

 

위 메소드는 ObjectInput 인터페이스를 구현하는 ObjectInputStream 클래스에서 메소드를 정의한다.

 

ObjectInputStream 을 hierarchy 이다.

 

직렬화랑 같다. ObjectInputStream 도 java.io.InputStream 을 상속받고 있다. 

그러므로 직렬화된 바이트 스트림 데이터 Input 형식에 따라 InputStream 을 주입하고 readObject 를 호출하면 된다.

 

다시 객체로 돌아갈때 편의를 위해 Object 로 반환 타입을 해둔다.

 

 

2. 직렬화 역직렬화 예시


예시를 내가 찾아보자.

 

 

 

 

 

 

 

3. 마치며


아마 알게 모르게 객체들이 다 json 으로 변환된 수 있었던 이유는

직렬화가 되어 있었기 때문일 것이다.

 

우리가 모르고 있었지만, 그런 기능이 다 제공이 되었던 거였다...

 

열심히 공부를 해보자.

 

 

 

참고


ref: https://www.baeldung.com/java-serialization#java-serialization-caveats
ref: https://techblog.woowahan.com/2551/
ref: https://mark-kim.blog/why_not_recommend_java_serialization/java_serialization/
728x90