대충 넘어가지 않는 습관을 위한 기록

@NoArgsConstructor(access = AccessLevel.PROTECTED)를 쓰는 이유

uhyvn 2023. 11. 16. 23:00

@NoArgsConstructor(access = AccessLevel.PROTECTED) 

- 이렇게 하면 해당 클래스를 상속받은 하위 클래스에서만 기본 생성자를 호출할 수 있습니다. 외부에서는 직접 접근할 수 없습니다.

 

 

보통 Entity 클래스에서 사용된다.

private도 아니고, public도 아니고 굳이 protected여야만 하는 이유는?

 

1. 객체 생성 제한

- 객체의 불변성 및 무결성을 유지하고, 객체의 생성을 제어하여 안정성을 높이는 데 도움이 된다.

- 일단 Entity를 어디에서든 막 갖다 쓰는 것 자체가 말이 안되기 때문에, 안정성 측면은 확실히 이해가 됨.

 

2. JPA 요구사항 충족

- JPA 공식 문서에 " Entity Class는 반드시 매개변수가 없는 public 또는 protected의 생성자를 가져야 한다." 라고 되어있다.

JPA는 Entity 객체를 인스턴스화하고 필드에 값을 채워넣기 위해 Reflection을 사용해 런타임 시점에 동적으로 기본생성자를 통해 클래스를 인스턴스화하여 값을 매핑하기 때문이다.

- 이 때, Entity Class에 기본생성자가 존재하지 않는다면 JPA는 Entity 객체를 동적으로 인스턴스화 할 수 없으므로 JPA의 기능을 원활하게 사용하지 못한다.

 

- 그렇다면 기본 생성자의 접근제어자를 왜 Private이 아닌 Public 또는 Protected로만 제한할까?

- JPA는 다른 Entity와 연관관계를 갖는 Entity를 조회할 때, 연관된 Entity 객체를 함께 가져오는 즉시로딩(EAGER)과 연관된 Entity 객체를 실제로 조회할 때 가져오는 지연로딩(LAZY) 이렇게 두 가지 전략을 선택하여 사용할 수 있다.

- 즉시로딩(EAGER)의 경우에는 Entity 조회 시 연관된 Entity 객체를 즉시 조회하지만, 지연로딩(LAZY)의 경우에는 Entity 조회 시 연관된 Entity 객체는 Proxy 객체로 존재한다.

이 때, 연관된 Proxy Entity 객체에 직접 접근 할 때, 쿼리가 수행되며 실제 값을 가져오는 것이다.

 

- LAZY일 때 Proxy 객체는 Entity Class를 상속받아 만들어진 객체이므로 Entity의 기본생성자에 대한 접근제어자가 Private일 시 Entity Class를 상속 받을 수 없어 Proxy 객체를 생성 할 수 없다.

- 즉, JPA가 Entity Class를 상속받는 Proxy 객체를 생성하기 위해 Entity Class의 기본생성자는 Public 또는 Protected의 접근제어자를 가져야 한다.

 


 

- 그렇다면 기본 생성자를 Public이 아닌 Protected로 제한하였을 때 가지는 장점은?

 

기본적으로 객체를 생성하고 값을 채워넣는 방식은 크게 3가지로 분류된다.

1. 기본생성자를 통해 객체 생성 - setter를 통해 필드값 주입

2. 매개변수를 가지는 생성자를 통해 객체 생성과 동시에 필드값 초기화

3. 정적 팩토리 메서드 (static factory method) 또는 빌더 (builder) 패턴을 통해 객체 생성과 동시에 필드값 초기화

 

첫 번째, 기본생성자로 객체 생성 후 setter를 통해 필드값을 주입하는 방법은 객체 값의 변경 가능성을 열어두는 것이므로 권장하는 방법이 아니다.

setter를 통해 언제 어디서든 객체의 값이 변경될 수 있으므로 추후 객체의 값이 어디서 변경되었는지 추적하기 어렵고, 객체의 일관성 유지에도 좋지 않다.

 

2, 3의 방법을 권장하게 됨으로써 객체 생성 시 아무런 매개변수를 가지지 않는 기본생성자는 그저 JPA의 Entity Class의 요구사항 이외에는 사용할 일이 없게 된다. 이러한 기본 생성자를 Public으로 열어두는 것은 여러 위치에서 무분별한 객체 생성을 야기하는 원인이 된다.

 


 

이러한 이유로, 객체의 변경점을 줄이고 객체의 일관성을 유지하기 위해 매개변수를 가지는 생성자 또는 정적 팩토리 메서드를 통해 객체를 생성할 수 있도록 하고 무분별한 객체 생성을 방지하기 위해 기본 생성자의 접근제어자는 Protected로 제한함으로써 최대한 접근 범위를 작게 가져가는 것이다.

 

 

 

 


https://hungseong.tistory.com/70