Post

마샬링과 직렬화

마샬링과 직렬화

image

직렬화와 마샬링은 거의 비슷하게 사용된다. 위에 사진과 같이 마샬링이 직렬화보다 더 큰 범위를 가지며, 직렬화는 마샬링의 한 부분이다.


마샬링 (Marshalling)

마샬링은 직렬화와 거의 비슷한데 다른점은 코드베이스를 포함하여 객체를 직렬화 한다.

image

코드베이스?

코드베이스는 객체를 받는이에게 이 객체의 구현을 어디서 찾을 수 있는지에 관한 정보를 말한다. 만약 다른 프로그램에게 객체를 전달했는데 이 객체를 다시 사용 하려면 데이터 타입에 관한 정보가 있어야 한다. 코드베이스는 이 데이터가 어디에 있는지 알려주는 정보를 말한다.

코드베이스가 있기 때문에, 객체의 정보를 알지 못하는 다른 JVM에게 마샬링을 통해서 건네주면, 그 JVM이 언마샬링을 통해, 객체를 원래 상태로 되돌릴 수 있다. 이런 장점을 통해 RMI 같은 기능을 사용할 수 도 있다.

RMI (Remote Method Invocation)
RMI을 사용하면 자바에 분산 애플리케이션 메카니즘 API를 제공할 수 있다. RMI는 객체가 다른 JVM에서 실행중인 객체에서 메서드를 호출할 수 있다.

java에서 마샬링 직렬화 차이??

Marshalling과 Serialization을 유사하다고 한다. 위키피디아에 따르면 파이썬 표준라이브러리에서는 직렬화와 마샬링은 동일하게 간주된다고 한다. 근데 자바에서는 굳이 구분하는데 뭐가 다를까?

Marshalling은 코드베이스를 기록하지만 직렬화는 하지않는 점이 다르다고 한다. 즉 원격 프로시저를 호출하는 것에서는 유사하지만 다른 목적을 가졌다는 것이다. Marshaling은 원격 프로시저를 호출할때 함수의 parameter, return value들을 전달할 수 있는데 반해 Serialization은 구조화된 데이터를 byte stream과 같은 형식으로 복사하는 것을 의미한다.

이해하기가 어렵다. 쉽게 이야기하면 직렬화는 객체 자체를 복사하는 개념이고 마샬링은 코드베이스를 가져와 만드는 개념이다.

그래서 객체를 이용하지 않는 다른 언어 또는 플랫폼간의 통신할때 주로 Marshaling을 과정을 통한다. 그리고 네트워크나 객체 싱크에는 Serialization을 많이 이용한다.

java에서 마샬링 예시를 검색하게 되면 java 객체를 xml로 바꾸는 예제가 많이 나온다.

java에서 다른 언어 또는 플랫폼간의 통신할 떄는 마샬링이라는 용어를 사용하고, 네트워크나 객체 싱크에는 직렬화 용어를 사용하는 것 같다.


직렬화 (Serialization)

직렬화는 객체의 필드를 바이너리 형식이나 바이트스트림으로 바꾸는 작업을 말한다. 굳이 바이트 스트림이 아니여도 파일이나, 메모리, 데이터베이스 등으로 바꾸는 작업도 포함된다.

JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 직렬화 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 역직렬화가 있다.

image

바이트스트림 (Byte Stream)
스트림은 데이터 배열이다. Input Stream은 데이터를 읽으며 Output Stream은 데이터를 쓰는 작업이다. 자바 바이트 스트림은 바이너리 파일같은 로우 데이터를 처리하는데 알맞다.

자바에서는 객체의 직렬화, 역직렬화를 위해 ObjectInputStream과 ObjectOutputStream을 제공한다.

1
2
3
4
5
6
7
// 객체를 직렬화하여 파일에 저장
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objectfile.ser"));
oos.writeObject(new Member());

// 파일로부터 객체를 읽어 객체 생성
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objectfile.ser"));
Member member = (Member) ois.readObject();  // Object로 리턴되므로 명시적 형변환 필요

직렬화 적용 분야

  • 파일 저장소
    • 프로그램 실행 중에 생성된 데이터를 파일시스템에 저장한 후, 이후에 프로그램이 다시 실행되었을 때 저장된 데이터를 다시 사용한다.
  • 네트워크 통신
    • 네트워크 상에 떨어져 있는 프로그램 간에 데이터를 주고 받기 위해 데이터를 직렬화한 후, 패킷(packet)에 담아 전송한다.
  • 데이터베이스
    • 복잡한 형태의 객체를 데이터베이스에 저장할 때 직렬화한 문자열 형태로 테이블의 컬럼에 저장하기도 한다.
  • 웹 환경
    • 웹 서버에서 브라우저(클라이언트)로 구조화된 데이터를 전송할 때 직렬화 한 후 (JSON 형식 등) 전달하는 방식

Serializable

java.io.Serializable 인터페이스를 구현한 클래스만 객체를 직렬화 할 수 있다.

  • 상속(is-a)
    • 부모 클래스가 Serializable을 구현하면
      • 자식 클래스는 항상 직렬화가 가능하다.
      • 자식 클래스를 직렬화 하면 부모 클래스의 인스턴스 변수도 함께 직렬화 된다.
    • 자식 클래스만 Serializable을 구현하면
      • 부모 클래스의 인스턴스 변수는 직렬화되지 않는다.
      • 부모 클래스의 인스턴스 변수도 직렬화 대상에 포함하려면 두 가지 방법이 있다.
        • 조상 클래스가 Seializable을 구현한다.
        • 직렬화 코드를 직접 구현한다.
  • 포함 (has-a)
    • 클래스가 직렬화 할 수 없는 객체를 인스턴스 변수로 참조하고 있으면
      • 직렬화 불가
      • 직렬화 불가한 인스턴스 변수에는 transient를 붙여 제외하고 직렬화 가능

직렬화 코드 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Student implements Serializable {
    public static final long serialVersionUID = 1234L;

    private  long studentId;
    private String name;
    private transient int age;

    public Student(long studentId, String name, int age) {
        this.studentId = studentId;
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "studentId=" + studentId +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

serialVersionUID

직렬화 수행 시 클래스 정보를 가지고 생성되는 클래스의 버전 값, 역직렬화 수행 시 이 값을 가지고 비교해서 일치해야 한다. serialVersionUID를 선언하지 않으면 JVM에서 자동으로 생성해준다. 그러나 명시하는 것을 권장사항으로 하고 있다. 그 이유는 Class가 update 될 경우 serialVersionUID가 변경 될 수 있기 때문이다.

transient

JPA에서 데이터베이스에 연관 짓고 싶지 않은 변수위에 @Transient 어노테이션을 선언하는데 여기서도 같은 역할을 한다. transient 표시되어 있는 변수는 직렬화에서 제외되어 write와 read하지 않는다.

JSON 직렬화, 역직렬화

지금까지는 객체 직렬화를 JVM과 ObjectInputStream/ObjectOutputStream에 위임하는 방식이었지만 XML, JSON과 같은 포맷을 이용한 직렬화도 가능하다. 이로 인한 장점은 다른 환경, 다른 언어로 만들어진 어플리케이션과도 통신이 가능해진다는 것이다.

JSON 파싱, 처리 라이브러리를 사용하여 자바 객체를 JSON으로 직렬화하거나 JSON 데이터를 자바 객체로 역직렬화할 수 있다. (JackSon 등 사용)

JPA Entity에 Serializable을 꼭 상속해야 할까?

직렬화는 JVM 메모리에 상주되어 있는 객체 데이터를 그대로 영속화 할 때 사용된다. 시스템이 종료 되더라도 없어지지 않고 영속화 되어 네트워크로 전송도 가능하다.

따라서, 이 객체를 어딘가로 전송하거나 세션에 기록하거나 등등 정말 serialization을 위한 용도가 아니라면, Hibernate 상에서는 굳이 Serializable을 구현하지 않아도 되지만, 그래도 Serializable을 구현하는 것이 좋은 습관이라고 한다.

참고 : https://bvaisakh.wordpress.com/2015/03/04/do-jpa-entities-have-to-be-serializable/

직렬화가 필요한 이유?

어떤 개발 언어든, 사용하는 데이터의 메모리 구조는 크게 2가지로 나뉜다.

  • 값 형식 데이터
    • int, float, char 등 값 형식 데이터는 스택에 메모리가 쌓이고 직접 접근이 가능하다.
  • 참조 형식 데이터
    • 객체와 같은 참조 형식 변수를 선언하면 힙에 메모리가 할당되고, 스택에서는 이 힙 메모리를 참조하는 구조로 되어있다.

위 두가지 데이터 중에서 디스크에 저장하거나 통신할 때는 값 형식 데이터만 사용할 수 있다. 참조 형식 데이터는 실제 데이터 값이 아닌 힙에 할당되어 있는 메모리 번지 주소를 가지고 있기 때문이다.

예를 들어, 객체 A를 만들고 주소 값이 0x00045523라고 가정하자. 그리고 이 값을 파일에 포함하여 저장했다고 해보자. 이후 프로그램을 종료하고 다시 실행해서 주소 값 0x00045523을 가져오더라도 기존 A 객체의 데이터를 가져올 수 없다. 프로그램이 종료되면 기존에 할당되었던 메모리(0x00045523)는 해제되고 없어지기 때문이다.

네트워크 통신 또한 마찬가지이다. 각 PC마다 사용하고 있는 메모리 공간 주소는 전혀 다르다. 그러므로 내가 다른 PC로 전송한 A 객체 데이터(0x00045523)는 무의미하다. 이 데이터를 받은 PC의 메모리 주소 0x00045523에는 전혀 다른 값이 존재하기 때문이다.

직렬화를 하게 되면 각 주소 값이 가지는 데이터를 전부 끌어 모아서 값 형식 데이터로 변환해 준다. 직렬화가 된 데이터는 언어에 따라서 텍스트 또는 바이너리 등의 형태가 되는데, 이러한 형태가 되었을 때 저장하거나 통신할 때 파싱이 가능한 유의미한 데이터가 된다.

즉, 직렬화를 하는 이유는 사용하고 있는 데이터를 파일 저장 혹은 데이터 통신에서 파싱할 수 있는 유의미한 데이터를 만들기 위함이다.

java 직렬화의 장점

  • 자바 직렬화는 자바 시스템에서 개발에 최적화되어 있다.
  • 복잡한 데이터 구조의 클래스의 객체라도 직렬화 기본 조건만 지키면 큰 작업 없이 바로 직렬화, 역직렬화가 가능하다.
  • 데이터 타입이 자동으로 맞춰지기 때문에 역직렬화가 되면 기존 객체처럼 바로 사용이 가능하다.

Reference

https://donghyeon.dev/2020/11/07/%EC%A7%81%EB%A0%AC%ED%99%94%EC%99%80-%EB%A7%88%EC%83%AC%EB%A7%81/

https://jongminlee0.github.io/2020/03/15/serializable/

https://bravenamme.github.io/2020/02/05/java-serializable/

https://atoz-develop.tistory.com/entry/JAVA%EC%9D%98-%EA%B0%9D%EC%B2%B4-%EC%A7%81%EB%A0%AC%ED%99%94Serialization%EC%99%80-JSON-%EC%A7%81%EB%A0%AC%ED%99%94

https://stackoverflow.com/questions/770474/what-is-the-difference-between-serialization-and-marshaling

https://steady-coding.tistory.com/576

https://duehd88.tistory.com/entry/java-Mashalling%EA%B3%BC-Serialization%EC%9D%98-%EC%B0%A8%EC%9D%B4

This post is licensed under CC BY 4.0 by the author.