티스토리 뷰

📗 내 코드

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder(access = AccessLevel.PRIVATE)
public class Book { ... }

 

Book 엔티티 코드를 살펴보자. 도서 관련 백엔드 서비스이므로 당연히 Book 엔티티는 존재한다.

여기서 살펴볼 것은

@NoArgsConstructor(access = AccessLevel.PROTECTED)

 

👆 이 부분이다.

 

왜 사용했나?

정말 솔직하게 말하면 이 프로젝트 이전 팀 프로젝트에서 팀원 분이 베이스 코드 작성 시에 위처럼 코드를 작성하셨다.

그 때는 내가 맡은 부분에만 정신이 팔려서 사실 저 코드 쓰임의 이유를 못 여쭤봤다.(내가 찾아봤어야 하는건데 말이다.)

그래서 좋은 게 좋은거지 라는 안일한 생각으로 버드북 프로젝트에 그대로 가져왔다.

그럼 왜 @NoArgsConstructor 어노테이션에 access 레벨을 proteced로 지정하는걸까?

 

@NoArgsConstructor

@NoArgsConstructor 어노테이션은 파라미터가 없는 디폴트 생성자를 생성하는 어노테이션이다.

 

즉, Book엔티티를 예시로 보면

public Book() {}

이 생성자를 알아서 만들어준다는 소리다.

JPA는 기본 스펙 상 기본 생성자를 요구한다. JPA는 리플렉션을 사용해서 내부적으로 엔티티를 생성하는데 이 때 동적으로 런타임 시점에 기본 생성자를 통해 클래스를 인스턴스화 한다.

즉, 직접 기본 생성자를 작성하든 어노테이션을 통해서 생성하든 해야한다는 소리다.

 

@NoArgsConstructor(access = AccessLevel.PROTECTED)

외부에서 무분별한 불완전한 객체 생성을 방지하기 위해 기본 생성자에 접근 제한을 건다.

 

그럼 일단 JPA를 사용하기 위해 기본 생성자가 필요하단 것은 이해했다.

그러면 왜 접근 제한을 두는걸까? 즉, AccessLevel을 왜 설정하는걸까?

 

외부에서 기본 생성자로 객체를 생성하는 것을 방지하기 위함이다.

 

기본 생성자 생성에 접근 제한을 걸지 않았을 때를 가정해보자

@Entity
@Getter
@NoArgsConstructor
public class Book { ... }

이렇게 되면 외부에서 기본 생성자를 통해 객체 생성이 자유로워진다.

그러면 아무런 필드 값을 가지지 못한 불완전한 Book 객체가 생성될 수 있고, 이는 비즈니스 로직이나 데이터베이스와의 상호작용에서 예외를 발생시킬 가능성이 높다.

 

또한, 완전한 객체를 만들기 위해서 setter를 함께 쓴다고 가정해보자.(위의 코드에서 @Setter 어노테이션을 추가했다고 가정한다.)

setter는 객체 생성 시 지양하는 방법이다. setXX()를 사용하면 어디든 객체의 값을 변경할 수 있다. 즉, 객체의 일관성을 유지하기가 어렵고 데이터베이스의 일관성 또한 깨지기 쉽다.

 

결국 기본 생성자에 접근 제한을 걸어서 외부에서 무분별한 불완전한 객체 생성을 방지하는 것이다.

 

access = AccessLevel.PROTECTED

접근 권한을 Protected로 설정하는 이유는 엔티티의 프록시 조회 때문이다.

 

위의 예시에서 접근 권한을 그냥 Public으로 해주면 안되는 이유를 살펴보았다.

그렇다면 왜 접근 권한이 Protected인가?

 

엔티티끼리 연관관계를 맺게되면 지연 로딩의 경우에 실제 엔티티가 아니라 프록시 객체를 조회한다.(프록시에 대해선 다음에 알아보자..)

암튼 JPA의 구현체는 실제 엔티티의 기본 생성자를 통해 프록시 객체를 생성한다. 

이 때 접근 권한을 private으로 하면 프록시 객체를 생성할 수가 없다. 즉, 지연 로딩 시 값을 조회할 수가 없다.

 

결론은?

무분별한 객체 생성을 막고, 프록시 객체 생성을 통한 조회를 위해 기본 생성자 생성 @NoargsConstructor 어노테이션의 접근 제한은 Protected로 하자

 

고민할 지점을 알려주신 팀원 분께 감사드린다!

 

참고 자료

https://velog.io/@kevin_/%EB%82%B4%EA%B0%80-NoargsConstructor-access-AccessLevel.PROTECTED%EB%A5%BC-%EC%99%9C-%EC%9E%91%EC%84%B1%ED%96%88%EC%9D%84%EA%B9%8C

 

내가 @NoArgsConstructor (access = AccessLevel.PROTECTED)를 작성했던 이유

그 때 당시에는 Spring은 물론 Java에 대한 개념도 매우 약할 때라 지금도 약하지만레퍼런스의 코드를 가져다 사용하기에 급급했다.당시의 나는 해당 개념에 대한 정확한 이해보다는 기능 구현이

velog.io

https://erjuer.tistory.com/106

 

[JPA] Entity Class의 @NoargsConstructor (access = AccessLevel.PROTECTED)

실무에서 JPA를 활용하다보면 Entity 생성시 @NoargsConstructor (access = AccessLevel.PROTECTED) 이라는 Annotation을 붙여서 개발을 하게 된다. 이에 조금 더 정확히 이해하고자 이번 블로그 글로 언급하고자 한

erjuer.tistory.com

 

🐤📖

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함