[JAVA] 자바에서 말하는 직렬화 ? 역직력화?
HTTP | JSON |
JAVA | 객체 |
HTTP에서는 JSON을, 자바에서는 객체를 사용합니다.
하지만 서로 형식이 다르기 때문에 혁식에 맞게 변환하는 작업이 필요합니다.
이러 작업들을 직렬력화, 역직렬화라고 합니다.
직렬화(Serialize)란?
자바 시스템 내부에서 사용되는 객체를 외부에서 사용하도록 데이터를 변환하는 작업.
자바 언어에서 사용되는 Objct또는 Data를 다른 컴퓨터의 자바 시스템에서도 사용할 수 있도록 바이트스트림(stream of bytes) 형태로 연속적인(serial)데이터로 변환하는 포맷 변환 기술을 일컫는다.
EX) title은 "제목", content는 "내용"이라는 값이 들어 잇는 객체가 있다고 가정을 들겠습니다.
이 때 이객체를 JSON형식으로 직렬화할 수 있습니다.
[바이트 스트림이란?]
스트림은 클라이언트나 서버 간에 출발지 목적지로 입출력하기 위한 데이터가 흐르는 통로를 말한다.
자바는 스트림의 기본 단위를 바이트로 두고 있기 때문에, 네트워크, 데이터베이스로 전송하기 위해 최소 단위인 바이트 스트림으로 변화하여 처리한다.
역직렬화( Deserialize )란?
직렬화의 반대입니다. 외부에서는 사용하는 데이터를 자바의 객체 형태로 변환하는 작업.
JSON형식의 값을 자바 객체에 맞게 변환 하는 것도 역직렬화.
직렬화를 사용하는 이유?
직렬화를 응용한다면 휘발성이 있는 캐싱 데이터를 영구 저장이 필요할 때 사용할 수도 있다.
예를들어 JVM의 메모리에서만 상주되어 있는 객체 데이터가 시스템이 종료되더라도 나중에 다시 재사용이 될 수 있을 때 영속화를 해두면 좋다. 이러한 특성을 살린 자바 직렬화는 실제로도 여러곳에 응용된다.
서블릿 세션 (Servlet Session)
- 단순히 세션을 서블릿 메모리 위에서 운용한다면 직렬화를 필요로 하지 않지만, 만일 세션 데이터를 저장 & 공유가 필요할때 직렬화를 이용한다.
- 세션 데이터를 데이터베이스에 저장할때
- 톰캣의 세션 클러스터링Visit Website을 통해 각 서버간에 데이터 공유가 필요할때
캐시 (Cache)
- 데이터베이스로부터 조회한 객체 데이터를 다른 모듈에서도 필요할때 재차 DB를 조회하는 것이 아닌, 객체를 직렬화하여 메모리나 외부 파일에 저장해 두었다가 역직렬화하여 사용하는 캐시 데이터로서 이용이 가능하다.
- 물론 자바 직렬화를 이용해서만 캐시를 저장할 수 있는 것은 아니지만 자바 시스템에서 만큼은 구현이 가장 간편하기 때문에 많이 사용된다고 보면 된다.
- 단, 요즘은 Redis, Memcached 와 같은 캐시 DBVisit Website를 많이 사용하는 편이다.
자바 RMI (Remote Method Invocation)
- 자바 RMI는 원격 시스템 간의 메시지 교환을 위해서 사용하는 자바에서 지원하는 기술이다.
- 이 메세지에 객체 데이터를 직렬화하여 송신하는 것이다.
- 최근에는 소켓을 이용하기 때문에 안쓰이는 기술이다.
Serializble인터페이스
우선 객체를 직렬화하기 위해선 java.io.Serializble인터페이스를 implements 해야합니다.
그렇지 않으면 NotSerializableException런타임 예외가 발생됩니다..
import java.io.ByteArrayOutputStream;
public class Member implements Serializable {
private String name;
private String email;
private int age;
public Member(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
@Override
public String toString(){
return String.format("Member{name='%s', email='%s', age='%s'}", name, email);
}
}
ObjectInputStream과 ObjectOutputStream
자바에서는 객체의 직렬화, 역직렬화를 위해 ObjectInputStream과 ObjectOutputStream을 제공합니다.
ObjectOutputStream
- 직렬화: 스트림에 객체를 출력하기 위해 사용
- wirteObject() 메소드 같이 사용
ObjectInputStream
- 역직렬화: 스트림으로부터 객체를 입력받기 위해 사용
- readObject(): Object로 리턴되므로 형변환 필요
writeObject()/readObject()뿐만 아니라 primitive(기본, 원시)타입에 대응하는 메소드도 제공됨
예제1)
public static void main(String[] args) throws IOException {
// 직렬화할 멤버 객체
Member member = new Member("김배민", "coco@naver.com", 10);
byte[] serializeMember;
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()){
try(ObjectOutputStream oos = new ObjectOutputStream(baos)) {
// 직렬화 가능 객체를 바이트 스트림으로 변환하고 파일에 저장
oos.writeObject(member);
// serializedMember -> 직렬화된 member 객체
serializeMember = baos.toByteArray();
}
}
//바이트 배열로 생성된 직렬화 데이터를 base64로 변환
System.out.println(Base64.getEncoder().encodeToString(serializeMember));
}
그럼 결과적으로 member객체는 직렬화 되어 이러한 출력값을 얻을 수 있음.
예제 2)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Member2 implements Serializable {
private String name;
private String email;
private int age;
public Member2(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
@Override
public String toString() {
return "Member2 [name=" + name + ", email=" + email + ", age=" + age + "]";
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 개별 직렬화, 역직렬화
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize_test.ser"));
oos.writeObject(new Member2("아이유", "iu@naver.com", 24));
oos.writeObject(new Member2("지수", "jisu@naver.com", 20));
oos.writeObject(new Member2("유진", "uzin@naver.com", 21));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("serialize_test.ser"));
System.out.println(ois.readObject());
System.out.println(ois.readObject());
System.out.println(ois.readObject());
System.out.println("=====================================================");
// ArrayList에 담아 직렬화
List<Member2> memberList = new ArrayList<>();
memberList.add(new Member2("아이유", "iu@naver.com", 24));
memberList.add(new Member2("지수", "jisu@naver.com", 20));
memberList.add(new Member2("유진", "uzin@naver.com", 21));
oos.writeObject(memberList);
System.out.println(ois.readObject());
}
}