728x90
Serializable은 물론 편리하다. 그러나 버그와 보안 문제가 일어날 가능성이 커질 수 밖에 없다.
이럴 때 '직렬화 프록시 패턴' 을 사용하자.
직렬화 프록시는 readObject 의 방어적 복사보다 강력하다.
[ 직렬화 프록시 패턴을 사용하는 방법 ]
- 바깥 클래스의 논리적 상태를 정밀히 표현하는 중첩 클래스를 설계하고, private static 으로 선언하기
- 위 '중첩 클래스'가 바로 바깥 클래스의 직렬화 프록시다.
- 중첩 클래스의 생성자는 단 하나여야 하며, 바깥 클래스를 매개변수로 받는다.
- 중첩 클래스의 생성자는 인수로 넘어온 인스턴스 데이터를 복사한다.
- 일관성 검사나 방어적 복사는 필요하지 않다.
- 직렬화 프록시의 기본 직렬화 형태는 바깥 클래스의 직렬화 형태로 쓰기에 이상적이다.
- 바깥 클래스와 직렬화 프록시 모두 Serializable을 구현했다고 선언해야 한다.
[ 직렬화 프록시를 사용하면 얻을 수 있는 장점 ]
- 직렬화는 생성자를 이용하지 않고도 인스턴스를 생성하는 기능을 제공하는데, 이 패턴은 직렬화의 이런 특성을 제거한다.
- 역직렬화된 인스턴스가 불변식을 만족하는지 검사할 수단을 강구하지 않아도 된다.
- 가짜 바이트 스트림 공격과 내부 필드 탈취 공격을 프록시 수준에서 차단해준다
- 필드들을 final로 선언해도 되므로 바깥 클래스를 진정한 불변으로 만들 수 있다.
- 어떤 필드가 기만적인 직렬화 공격의 목표가 될 지 고민하지 않아도 된다.
- 역직렬화때 유효성 검사를 하지 않아도 된다
- 역직렬화한 인스턴스와 원래의 직렬화된 인스턴스의 클래스가 달라도 정상 작동한다. (은근 쓸모 있다.)
[ 직렬화 프록시 패턴의 한계 ]
- 클라이언트가 멋대로 확장할 수 있는 클래스에는 적용할 수 없다
- 객체그래프 순환이 있는 클래스에는 적용할 수 없다.
- (이런 객체 메서드를 직렬화 프록시 readResolve 안에서 호출하려 하면 ClassCastException이 발생한다.)
- 직렬화 프록시만 가졌을 뿐, 실제 객체가 만들어진 것은 아니기 때문이다.
- 방어적 복사보다 느리다.
- 약 14%
핵심 정리
제3자가 확장할 수 없는 클래스라면 가능한 한 직렬화 프록시 패턴을 사용하자.
이 패턴이 아마도 중요한 불변식을 안정적으로 직렬화해주는 가장 쉬운 방법이다.
728x90
'JAVA > Effective Java' 카테고리의 다른 글
Effective Java (7) | 2022.09.15 |
---|---|
item 89. 인스턴스 수를 통제해야 한다면 readResolve보다는 열거 타입을 사용하라 (0) | 2022.09.15 |
item 88. readObject 메서드는 방어적으로 작성하라 (0) | 2022.09.13 |
item 87. 커스텀 직렬화 형태를 고려해보라 (0) | 2022.09.13 |
item 82. 스레드 안정성 수준을 문서화하라 (0) | 2022.09.01 |
댓글