Reflection?
java에서는 reflection이라는 api를 제공한다.
reflection은 구체적인 클래스 타입을 알지 못해도 클래스의 메서드나, 타입, 변수들에 접근할 수 있도록 해주는 api이다
대표적인 적용 예시로는
1) JPA에서 객체 조회시 데이터가 들어가는 것
2) @RequestBody 사용 시 DTO 객체에 데이터가 들어가는 것
3) 테스트 케이스 작성시 private 메서드를 테스트할 때 등이 있다.
어떻게 가능한걸까?
기본적으로 객체에 데이터를 넣기 위해서는 일련의 과정(new, setter 등)이 필요하고, 접근 제어자에 따라 접근이 불가능한 것이 맞다.
하지만 reflection이 적용된다면 이러한 과정이 필요하지 않고 private 메서드의 접근도 가능하다.
바로 reflection이 static 영역에 저장되어 있는 클래스 정보에 접근이 가능하기 때문이다.
다만 reflection은 기본 생성자를 통해 객체를 생성하기 때문에 해당 클래스에 기본 생성자(빈 생성자)가 있어야 한다.
Reflection은 Spring Data JPA에서도 사용되었다
우리는 JPA에서 xxRepository.findById 메서드를 통해 객체를 조회할 수 있는데,
이러한 객체를 반환해주는 로직에서 reflection이 적용된 것이다.
Spring Data JPA와 기본 생성자 private이 불가한 이유?
Spring Data JPA에서 private 접근 제어자는 사용 불가능 한데, 이는 프록시와 관련이 있다.
지연로딩으로 인해 프록시 객체를 사용하는 경우 원본 엔티티를 상속한 프록시 객체를 생성하게 된다.
그 후 실제 사용 시점에 실제 엔티티 정보를 조회하여 프록시 엔티티가 원본 엔티티를 참조하도록 한다.
그러므로 기본 생성자에 private을 사용하게 된다면 상속받은 클래스(프록시 엔티티)에서 호출이 불가능하게 되고
public이나 protected 를 사용해야 한다는 오류가 발생하게 된다.
추가로 접근 제어자의 접근 허용 범위는 다음의 순서로 확장된다
private -> default -> protected -> public
protected : 동일 패키지의 클래스 또는 해당 클래스를 상속받은 다른 패키지의 클래스에서만 접근이 가능하다.
참고한 글
Spring data jpa에서 기본 생성자가 필요한 이유
https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/
https://da-nyee.github.io/posts/woowacourse-why-the-default-constructor-is-needed/
Spring data jpa에서 기본 생성자에 protected를 선언하는 이유
https://velog.io/@yyy96/JPA-%EA%B8%B0%EB%B3%B8%EC%83%9D%EC%84%B1%EC%9E%90