개발/Java

[JAVA] 직렬화 (Serialization)

hojak99 2016. 8. 3. 16:00

구글링을 통해서 가장 자세히 나와있는 블로그와 여러 블로그의 내용을 보고 작성했습니다. 출처는 밝히겠습니다.



직렬화(Serialization)란....


객체 직렬화의 기본적인 개념은 객체를 바이트 스트림으로 쓰고 읽게 하는 것이다.  이러한 스트림들은 서블릿에서 세션 상태 저장이나 RMI(Remote Method Invoation) 호출에서 파라미터 전송, 자바빈즈 컴포넌트에서 상태 정보 저장, 네트워크를 통한 객체 전송 등 많은 작업들에서 사용할 수 있다. 


장점 : 

객체 자체의 내용을 입출력 형식에 구애 받지 않고 객체를 파일에 저장함으로써 영속성을 제공할 수 있으며, 객체 자체를 네트워크를 통하여 교환할 수 있게 된다.





직렬화 기법 선택시 고려할 점

- 직렬화 기법에는 다양한 기법들이 존재하는데 특정 기술을 선택해서 적용을 해야만한다. 직렬화 기법을 선택하는 활용할 수 있는 기준들이 있는데 그 기준들은 다음과 같다


1. 단순성 (simple) : 

사용하기가 복잡하지 않아야 한다. 

직렬화를 위해 추가해야 할 코드가 적거나, 이상적인 것은 기존 코드를 변경하는 작업이 아예 없어야 한다.


2. 경량 (compact) : 

프레임워크 or 라이브러리의 규모가 작아야 한다.

프레임워크 혹은 라이브러리의 크기가 작다는 것은 추가 부담이 적어지므로 소규모 시스템에 적합. 

이상적인 것은 안드로이드 같은 모바일 시스템까지에서 구동될 수 있는 확률을 높다는 것을 의미


3. 유연성 (flexible) : 

객체의 데이터 구조는 설계 및 개발, 나아가 유지보수 단계에서 변화할 수 있다.

한정된 자료형만 직렬화할 수 있다면, 도입 자체가 불가능하거나 혹은 개발, 테스트 단계에서 오류를 유발하여 프로젝트의 실패의원인이 될 수도 있다.


4. 버전 지원 : 

객체의 데이터 구조는 설계 및 개발, 나아가 유지보수 단계에서 변화할 수 있다.

객체의 구조가 변경되더라도 클래스의 명칭을 변경하지 않고 새로운 버전을 부여할 수 있고, 서로 다른 버전의 객체들을 자동으로 변환(직렬화 및 역직렬화)해주는 기능을 프레임워크에서 제공해 줄 경우, 시스템의 유지관리가 용이해진다.


5. 속도 (fast) : 

처리 속도가 빠르면 빠를 수록 좋다.


6. 확장성 (scalability) : 

복잡하거나 거대한 형태의 데이터를 직렬하 할 수 있어야 한다.   

예를 들어 메모리 사용량이 많아 직렬화 대상 객체가 증가함에 따라 메모리 부족을 유발한다면 심각한 수준의 문제로 인해 직렬화프레임워크를 사용할 수 없게 된다.



직렬화 데이터 형식

- 직렬화된 데이터는 다양한 format으로 표현할 수 있다.


1. Binary : 

메모리에 저장된 데이터를 최소한의 가공 혹은 가공 없이 바이트의 연속된 형태로 저장하는 방식이나 사람이 읽기 불편하기 때문에 데이터의 무결성을 검사하기 어렵다.


2. JSON : 

텍스트 형식이므로 사람과 기계 모두 읽기 가능하다. 다양한 프로그래밍 언어에서 읽고 쓸 수 있기 때문에 널리 사용되며 XML에 비해 parsing 속도가 빠르다.


3. XML : 

텍스트 형식이며, JSON에 비해 복잡하다. JSON에 대해 가지는 장점은 스키마를 적용할 수 있어 데이터의 무결성을 검사할 수 있다는 점이다.


4. YAML : 

XML에 비해 사람이 읽고 쓰기 쉽도록 고안된 마크업 언어이다. 문법이 상대적으로 단순하고 가독성이 높게 설계 되 있다.






객체 직렬화를 하자!

- 객체 직렬화를 하기 위해서 ObjectInputStream 클래스와 ObjectOutputStream 클래스에서 제공해주는 여러가지 기능을 사용 할 수 있다.


먼저 ObjectInputStream 객체와 ObjectOutputStream  객체는 그 객체를 통하여 입출력된 객체들을 기억하여 동일한 객체를 중복하여 입출력된 객체들을 기억하며 동일한 객체를 중복하여 입출력하지 않도록 해준다.


이로 인해 객체 참조의 공유 및 원형 참조 문제를 해결해 주고 있다.

배열도 Object 이기 때문에 배열의 전송 시에도 객체 직렬화로 입출력할 수 있으며

애플릿을 객체 직렬화하여 전송하고자 할 경우, 애플릿 태그의 code 속성 대신 object 속성을 지정하면 직렬화된 객체를 전송할 수 있고 이 경우, 애플릿의 init() 메소드는 호출되지 않으며, start() 메소드만이 호출된다는 점에 유의해야 한다.



1. ObjectInput Interface :

- ObjectInput 인터페이스는 객체를 읽기 위한 기능을 포함하기 위해 DataInput 인터페이스를 확장하고 있다.

- DataInput 인터페이스는 여러 가지 기본형을 입력하기 위한 메소드를 포함하고 있으므로 ObjectInput 인터페이스는 객체, 배열, 문자열에 대한 입력 기능만 확장하면 된다.


2. ObjectOutput Interface :

- ObjectOutput 인터페이스는 객체를 쓰기 위한 기능을 포함하기 위해 DataOutput 인터페이스를 확장하고 있다.

- DataOutput 인터페이스는 여러 가지 기본형을 출력하기 위한 메소드를 포함하고 있으므로 ObjectOutput 인터페이스는 객체, 배열, 문자열에 대한 출력 기능만 확장하면 됩니다.


3. ObjectInputStream :

- ObjectInputStream 클래스는 ObjectOutputStream 객체에 쓰여진 여러 가지 기본형과 객체들을 읽어들여 먼저 직렬화를 해제하는 기능을 제공한다.

- ObjectInputStream 클래스와 ObjectInputStream 클래스는 FileOutputStream 클래스와 FileInputStream 글래스 등과 같이 사용됨으로써 객체를 영구적으로 보관할 수 있도록 해주고 이를 영속성이라고 한다.

따라서 ObjectInputStream 클래스는 파일에 저장되어 있는 객체나 네트워크를 통해 직렬화되어 전달된 객체를 직렬해제 하는 기능을 제공해 주고 있다.

- 주의할 점으로 java.io.Serializable 인터페이스와 java.io.Externalizable 인터페이스를 지원해 주는 객체에 대해서만 가능하다는 것이다. 이때 readObject() 메소드를 이용해 스트림으로부터 직렬화된 객체를 읽을 수 있으며 이렇게 읽은 객체는 배열, 문자열 또는 각 객체 등 원래의 형으로 캐스팅을 해 주어야 한다. 물론 자바의 기본형 데이터에 대해서는DataInput 인터페이스에서 정의하고 있는 메소드를 이용하여 각 기본형 값을 읽어들일 수 있다.


4. ObjectOutputStream :

- ObjectOutputStream 클래스는 여러 가지 기본형과 객체들을 주어진 출력 스트림에 출력하는 기능을 제공해 주고, 출력 스트림에 출력하기 전에 직렬화를 수행한다.

- ObjectOutputStream 클래스는 ObjectInputStream 클래스와 마찬가지로 FileOutputStream 클래스와 FileInputStream 클래스 등과 같이 사용됨으로써 객체를 영구적으로 보관할 수 있도록 하며 이를 영속성이라고한다.

따라서 ObjectOutputStream 클래스는 자바 기본형 데이터 또는 객체들을 파일에 저장하거나 네트워크를 통해 전달하기 위한 객체를 직렬화하는 기능을 제공해주고 있다.

- 주의할 점은, java.io.Serializable 인터페이스와 java.io.Externalizable 인터페이스를 지원해 주는 객체에 대해서만 가능하다는 것이다. 이 때, writeObject() 메소드를 이용하여 스트림에 직렬화된 객체를 쓸 수 있는데 물론 자바의 기본형 데이터를 쓰기 위해서는 DataOutput 인터페이스에서 정의하고 있는 메소드를 이용할 수 있고, 문자열을 쓰기 위해서는 writeUTF() 메소드를 이용할 수 있다..







ObjectInputStream 과 ObjectOutputStream 은 각각 InputStream 과 OutputStream을 직접 상속받지만 기반스트림을 필요로 하는 보조 스트림이기 때문에 객체를 생성할 때 입출력(직렬화/역직렬화)할 스트림을 지정해주어야 한다.



[그림 1 : ObjectInputStream 과 ObjectOutputStream]



파일에 객체를 저장(직렬화)하고 싶다면 밑에와 같이 하면 된다.


[그림 2 : 객체 직렬화]


위의 [그림 2]는 test.ser 이란 파일에 TestSeli 객체를 직렬화하여 저장하는데 출력할 스트림, FileOutputStream 을 생성해서 이를 기반스트림으로 하는 ObjectOutputStream을 생성한다. 

ObjectOutputStream의 writeObject(Object obj)를 사용해서 객체를 출력하면 객체가 파일에 직렬화되어 저장되는데 여기서 역직렬화 방법에 대해서 알아보자.



역직렬화는 직렬화할 때와는 달리 입력 스트림을 사용하고 writeObject(Object obj)대신 readObject()를 사용하여 저장된 데이터를 읽기만 하면 객체로 역직렬화된다. 여기서 주의할 점은 readObject()의 반환타입이 Object이기 때문에 객체 원래의 타입으로 형변환 해주어야 한다.


[그림 3 : 객체 역직렬화]




출처 : wiki.gurubee.net

반응형