Growth-Collectors / effective-java

repository for effective java study
3 stars 2 forks source link

아이템 90. 직렬화된 인스턴스 대신 직렬화 프록시 사용을 검토하라 #92

Open HanaHww2 opened 1 year ago

Tldkt commented 1 year ago

1. 직렬화 프록시 패턴이란?

class Period implements Serializable {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        this.start = start;
        this.end = end;
    }

    private static class SerializationProxy implements Serializable {
        private static final long serialVersionUID = 2123123123;
        private final Date start;
        private final Date end;

        public SerializationProxy(Period p) {
            this.start = p.start;
            this.end = p.end;
        }

        /**
         * Deserialize 할 때 호출된다.
         * 오브젝트를 생성한다.
         */
        private Object readResolve() {
            return new Period(start, end);
        }
    }

    /**
     * 이로 인해 바깥 클래스의 직렬화된 인스턴스를 생성할 수 없다.
     * 직렬화할 때 호출되는데, 프록시를 반환하게 하고 있다.
     *
     * Serialize할 때 호출된다.
     */
    private Object writeReplace() {
        return new SerializationProxy(this);
    }

    /**
     * readObject, writeObject 가 있다면, 기본적으로 Serialization 과정에서
     * ObjectInputStream, ObjectOutputStream이 호출하게 된다.
     * 그 안에 커스텀 로직을 넣어도 된다는 것.
     */
    private void readObject(ObjectInputStream stream) throws InvalidObjectException {
        // readObject는 deserialize할 때, 그러니까 오브젝트를 만들 때인데.
        // 이렇게 해두면, 직접 Period로 역직렬화를 할 수 없는 것이다.
        throw new InvalidObjectException("프록시가 필요해요.");
    }
}

SerializationProxy클래스는Period` 객체를 인자로 받아서, 해당 객체의 시작일과 종료일을 저장

SerializationProxy 클래스는 readResolve() 메서드를 오버라이드하여, 역직렬화할 때 프록시 객체(SerializationProxy)를 실제 객체(Period)로 변환합니다. 이렇게 함으로써, 직렬화된 객체가 역직렬화될 때 Period 객체를 생성하도록 보장

또한, Period 클래스는 readObject() 메서드를 오버라이드하여, 역직렬화할 때 직접 Period 객체를 생성할 수 없도록 함

→ 직렬화된 객체를 역직렬화할 때, 프록시 객체(SerializationProxy)를 거쳐서 실제 객체(Period)를 생성하게 되므로, 객체의 불변성과 안전성을 보장할 수 있습니다.

2. 직렬화 프록시 패턴의 장점

3. 직렬화 프록시 한계

  1. 클라이언트가 확장할 수 있는 클래스에는 적용 불가

확장 가능한 클래스는 하위 클래스가 생성될 때마다 이를 반영하여 새로운 직렬화 대상 클래스를 만들기 때문

  1. 객체 그래프 순환이 있는 클래스에는 적용 불가

직렬화 프록시는 객체 그래프에서 참조되는 모든 객체를 대상으로 직렬화를 수행하는데, 객체 그래프 순환이 있는 경우 무한루프에 빠질 가능성이 있기 때문

  1. 방어적 복사보다 느림
HanaHww2 commented 1 year ago