-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
📌 [아이템 90] 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라
✨ 핵심 내용
직렬화 프록시 패턴을 통해 Serializable의 위험을 크게 줄일 수 있다
⭐ 1. 바깥 클래스의 논리적 상태를 정밀하게 표현하는 중첩 클래스를 설계해 private static으로 선언한다
⇒ 이때 중첩 클래스가 바깥 클래스의 직렬화 프록시다
- 중첩 클래스의 생성자는 단 하나여야하고 바깥 클래스를 매개변수로 받아야한다
- 인스턴스의 데이터를 복사함
private static class Serializationproxy implements Serializable {
private final Date start;
private final Date end;
**SerializationProxy**(Period p) {
this.start = p.start;
this.end = p.end;
}
private static final long serialVersionUID =
234098243823485285L; // 아무 값이나 상관없다. (아이템87)
}- 바깥 클래스에 writeReplace 메서드를 추가한다
//직렬화 프록시 패턴용 writeReplace 메서드
private Object writeReplace() {
return new SerializationProxy(this);
}→ 자바의 직렬화 시스템이 바깥 클래스의 인스턴스 대신 SerializationProxy의 인스턴스를 반환하게 하는 역할을 함
즉, 직렬화가 이뤄지기 전에 바깥 클래스 인스턴스를 직렬화 프록시로 변환해줌
//직렬화 프록시 패턴용 readObject 메서드
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("프록시가 필요합니다.");
}→ 해당 메서드를 바깥 클래스에 추가하면 불변식 훼손 공격을 막을 수 있다
-
바깥 클래스와 논리적으로 동일한 인스턴스를 반환하는 readResolve 메서드를 SerializationProxy 클래스에 추가한다
→ 역직렬화 시 직렬화 시스템이 직렬화 프록시를 다시 바깥 클래스의 인스턴스로 변환하게 해준다
직렬화는 생성자를 이용하지 않고 인스턴스를 생성하는데, 해당 패턴은 이러한 상당 부분을 제거한다!
⇒ 일반 인스턴스를 만들 때와 똑같은 생성자, 정적 팩터리, 혹은 다른 메서드를 사용해 역직렬화된 인스턴스를 생성한다
→ 역직렬화된 인스턴스가 해당 클래스의 불변식을 만족하는지 검사할 다른 수단 필요 X
- 직렬화 프록시는 필드를 final로 선언해도되므로 클래스를 불변으로 만들 수 있다
- 직렬화 프록시 패턴은 역직렬화한 인스턴스와 원래의 직렬화된 인스턴스의 클래스가 달라도 정상 작동한다!
- ex) EnumSet
직렬화 프록시 패턴의 한계
- 클라이언트가 멋대로 확장할 수 있는 클래스(아이템 19)에는 적용할 수 없다
- 객체 그래프에 순환이 있는 클래스에 적용할 수 없다
- 대가가 따른다! 느리다!
💡 새롭게 알게 된 점
- 학습하면서 이전과 다르게 이해한 점이나 새롭게 알게 된 개념을 공유해주세요.
📚 정리
제3자가 확장할 수 없는 클래스라면 가능한 한 직렬화 프록시 패턴을 사용!
📢 댓글로 각자의 학습 내용을 공유해주세요!