Serializable 그저 바라만 보자
소주캉
직렬화가 뭐야?🤔
- 자바가 객체를 바이트 스트림으로 인코딩하고(직렬화) 그 바이트 스트림으로부터 다시 객체를 재구성하는(역직렬화) 메커니즘이다.
- 직렬화된 객체는 다른 VM에 전송하거나 디스크에 저장한 후 나중에 역직렬화할 수 있다.
객체를 저장한다는 게 무슨 의미인가?
- 새로운 객체는 오직 인스턴스 변수로만 구성된다.
- 객체의 동일성 판정은 두 객체의 인스턴스 변수의 값이 같고 다름을 비교한다!
- 클래스 변수나 메서드는 static 영역에 이미 적재되어 있다.
- 따라서 객체를 저장한다는 것은 객체의 모든 인스턴스 변수의 값을 저장한다는 의미이다.
- 객체를 저장, 전송하기 위한 방법으로
직렬화
가 등장한다.
직렬화 쓰지 말라는데?😮
직렬화가 등장한 이유
- 프로그래머가 어렵지 않게 분산 객체를 만들 수 있다고
생각했다
.
직렬화가 나쁜 이유👎
- 생성자가 보이지 않는다.
- API와 구현 사이 경계가 모호해진다.(캡슐화? 확장성? 그런 거 없음)
- 잠재적인 정확성 문제, 성능, 보안, 유지보수성이 안좋다.
readObject
메서드는 클래스패스 안의 거의 모든 타입의 객체를 만들 수 있다.
- 바이트 스트림 역직렬화 과정에서 메서드는 그 타입들 안의 모든 코드를 수행할 수 있다.
- 코드 전체가 공격 범위에 들어간다.
직렬화 위험 피하는 방법
쓰지 마라면 쓰지마~🤯
아무것도 역직렬화 하지 말자.
- 우리가 새로 만드는 코드에서 직렬화를 써야 할 이유는
전혀 없다
.
- 객체와 바이트 시퀀스를 변환해주는 다른 메커니즘을 사용하자.
그럼 다른 메커니즘은 뭔데??
직렬화
가 아닌 다른 객체를 저장할 방법을 쓰자!!!
- JSON(박재성씨 아님)
- 프로토콜 버퍼(Protocol Buffers, protobuf)
직렬화보다 뭐가 더 좋은데??
- 임의 객체 그래프를 자동으로 직렬화/역직렬화하지 않는다.
속성 - 값
쌍의 집합으로 구성된 간단하고 구조화된 데이터 객체를 사용한다.
- 기본 타입 몇 개와 배열 타입만 지원한다.
이래도 쓸거야?? 이래도?? 그러면...
- 객체 역직렬화 필터링(java.io.ObjectInputFilter) 사용하자.
- 데이터 스트림이 역직렬화되기 전에 필터를 설치한다.
- 특정 클래스를 받아들이거나 거부할 수 있다.
- 화이트리스트 방식을 사용하자(블랙리스트 노노)
Serializable 구현할 때 주의점🚧
문제점
구현 하면 수정하기 어려워진다👎
- Serializable 구현하면 직렬화 결과물도 공개 API가 된다.
- API 수정하면 직렬화 결과물도 수정해야 한다.
- 예시(arrayList)
- 직렬화 가능한 클래스를 수정해도 직렬화-역직렬화가 가능하게 하려면
serialVersionUID
를 다른 클래스와 다른 유일한 값으로 수동으로 넣어주어야한다.
- 그렇지 않으면 수정 전후 자동 생성된
UID
가 충돌하여 직렬화-역직렬화
가 실패한다.
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
private
, default
인스턴스 필드마저 공개된다(캡슐화 깨짐).
OCP
는 개나 줘버리게 된다.
버그와 보안 구멍 생길 위험이 높아진다👎
- 역직렬화는 생성자를 거치지 않는 우회 객체 생성 기법이다.
- 검증이 원활하게 이뤄지지 않을 수 있다.
테스트가 늘어난다👎
- Serializable 구현 클래스 수정되면
신버전과 구버전
사이에 직렬화-역직렬화 가능한지 검증해야 한다.
대처 방안
상속용 클래스, Interface에는 Serializable 구현하지 말자🏴☠️
- 위와 같은 문제점으로 기능 확장이 힘들어진다.
- 응~
객체지향
안하면 그만이야~ 라면 적극적으로 구현하자.
내부클래스도 하지 말자🏴☠️
- 내부 클래스는 바깥 인스턴스의 참조와 유효 범위 안의 지역변수 값들을 저장하기 위해 컴파일러가 생성한 필드들이
자동으로
추가된다.
자동으로
추가된 이 필드들의 직렬화 형태는 분명하지 않다
.
이런 것까지 해야되나? 싶으면 하라
이거 해도 되나? 싶으면 하지 마라
비공식 야전 교본, 개발자에게도 적용
궁금한데?
그럼 왜 자바에는 그렇게 Serializable 구현한 API가 많은가?
- 단지 레거시 때문인가?
- 객체를 캐싱하거나, 원격 메서드를 호출할 수 있다.
- 자바 내의 전송에서는
JSON
이나 XML
을 이용한 전송이 비효율적이다. 해당 parser
가 있어야 하기 때문이다.
참고