모르지 않다는 것은 아는것과 다르다.

Java

직렬화

채마스 2022. 5. 30. 23:55

개요

  • 자바에서 직렬화란 개념을 아주 가볍게 알고 있었다. 또한 종종 캐시를 사용할 때 Serializable 인터페이스를 구현해 본 경험이 있다.
  • 하지만 어떤 경우에 써야하는지 명확히 알지 못해 이번 기회에 개념을 잡아 보려고 한다.

 

직렬화란?

  • 자바에서 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술을 말한다.
  • 또한, 역직렬화란 바이트로 변환된 데이터를 다시 객체로 변환하는 기술을 말한다.
  • 정리하면, JVM의 메모리에 상주되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환하여 JVM으로 상주시키는 형태를 직렬화, 역직렬화라고 한다.

 

직렬화가 필요한 경우

  • JVM의 메모리에만 상주되어 있는 객체를 시스템이 종료되더라도 사라지지 않도록 영속화 하는 경우에 주로 사용된다.
    • 메모리 구조는 크게 값 형식 데이터(Value Type) 와 참조 형식 데이터(Reference Type) 이 있다는 것은 알고 있을 것이다.
    • PC 마다 메모리 공간 주소가 다르기 때문에 참조 형식 데이터를 전송하는데 직렬화가 필요한 것이다.
  • 서블릿 세션들은 대부분 세션의 자바 직렬화를 지원한다.
    • 사실 세션을 서블릿 메모리 위에서만 운용한다면 직렬화가 필요 없겠지만 파일로 저장하거나 세션 클러스터링을 형성하거나 DB를 저장하는 옵션등을 선택하는 경우 세션 자체가 직렬화되어 저장되어 전달된다.
  • 물론 캐시에서도 직렬화가 사용된다.

 

코드 예시

@AllArgsConstructor
public class Person implements Serializable {

    private String name;
    private int age;

}
  • 위와 같이 Serializable 인터페이스를 구현한다.
  • 아래와 같은 과정으로 직렬화 된다.

 

직렬화

public static void main(String[] args) {
    String path = "/Users/project/test";

    Person person = new Person("채마스", 28);
    saveObject(path, dto);
}

public void saveObject(String path, Person dto) {
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;
    try {
        fos = new FileOutputStream(path);
        oos = new ObjectOutputStream(fos);
        oos.writeObject(dto);

    } catch (Exception e) { 
        e.printStackTrace();
    } finally {
        if (oos != null) {
            try {
                oos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (fos != null) {
            try {
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
  • ObjectOutputStream 클래스를 사용해서 객체를 저장할 수 있다.
  • ObjectInputStream을 사용하면 저장해놓은 객체를 읽을 수 있다.
  • FileOutputStream 객체를 만든 후에 ObjectOutputStream의 매개변수로 넘기면, 객체가 파일에 저장된다.
  • 마지막으로 writeObject()를 통해서 매개변수로 넘어온 객체를 저장하고 파일을 보면 파일에 객체가 저장된 것을 확인할 수 있다.

 

역직렬화

public static void main(String[] args) {
    String path = "/Users/project/test";
    loadObject(path);
}

public void loadObject(String path) {
    FileInputStream fis = null;
    ObjectInputStream ois = null;
    try {
        fis = new FileInputStream(path);
        ois = new ObjectInputStream(fis);
        Object obj = ois.readObject();
        Person dto = (Person)obj;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (ois != null) {
            try {
                ois.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    if (fis != null) {
        try {
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 위와 같은 방식으로 파일에 저장된 객체 정보를 읽을 수 있다.

 

serialVersionUID 사용 시 주의할 점

public class Person implements Serializable {

    private static final long serialVersionUID = 1L;
}
  • serialVersionUID는 Java 직렬화 및 역직렬화 할때 필요한 버전 정보를 말한다.
  • Java 직렬화 대상 객체는 동일한 serialVersionUID를 가지고 있어야 한다.
  • serialVersionUID를 선언하지 않으면, 내부적으로 클래스의 구조 정보를 이용하여 자동으로 생성된 해시 값이 할당된다.
  • 만약 객체를 직렬화하고 클래스에 멤버변수가 추가된다면 java.io.InvalidClassException 예외가 터진다.

 

transient와 Serializable

  • transient 예약어를 사용하여 선언한 변수는 Serializable의 대상에서 제외된다.
  • 패스워드와 같이 보안상으로 중요한 데이터나 꼭 저장해야 할 필요가 없는 변수에 대해서는 transient를 사용할 수 있다.

 

정리

  • 직렬화는 서블릿 세션이나 캐시, 혹은 자바 RMI 등에 주로 사용된다.
  • 자바 직렬화는 자바 시스템에서 최적화 되어 있어서 직렬화 조건만 잘 지킨다면 복잡한 데이터 구조의 클래스를 직렬화, 역직렬화 할 수 있다.
  • 하지만 타입 체크가 엄격하고 용량도 json 과 같은 경량화된 데이터에 비해 훨씬 무겁다.
    • 긴 만료 시간을 가지는 데이터는 JSON 등 다른 포맷을 사용하여 저장 하는 것이 바람직하다.
  • 그렇기 때문에 외부 저장소로 저장되는 데이터는 짧은 만료 시간이 아니라면 자바 직렬화 사용을 지양한다.
  • 또한, 역직렬화 시 반드시 예외가 생길 수 있다는 점을 인지하고 필수적으로 예외처리를 해야한다.




REFERENCES

'Java' 카테고리의 다른 글

@SuppressWarnings  (0) 2022.05.30
ENUM 활용  (0) 2022.03.14
Method Reference  (0) 2022.03.06
Collectors (JAVA STREAM)  (0) 2022.03.06
LazyEvaluation,Curry,IntStream  (0) 2022.03.06