Spring Data Jpa 예제를 사용한 책들을 통해 공부를 하면 대부분 이렇게 사용을 한다.
// PostRepository.java
public interface PostRepository extends JpaRepository<Post, Long> {
}
// PostService.java
@RequiredArgsConstructor
@Service
public class PostService {
private final PostRepository postRepository;
...
}
RequiredArgsConstructor 는 Lombok의 어노테이션으로 final로 선언된 변수로 생성자를 자동으로 만들어준다. 그리고 생성자가 한 개만 있을 때는 @Autowired 어노테이션을 생략할 수 있다. 하지만 JpaRepository를 상속받은 PostRepository를 빈으로 등록하는 부분은 어디에도 없지만 service에서는 생성자를 통해 빈을 주입받고 있다. @Controller 나 @Service 어노테이션을 따라가보면 @Component 어노테이션이 있다.
@Component 어노테이션이 있으면 컴포넌트 스캔을 통해서 자동으로 빈이 등록된다. 하지만 JpaRepository를 따라가봐도 빈을 등록하는 코드는 없었다.
JpaRepository가 상속받고 있는 NoRepositoryBean에는 @Service 나 @Controller와는 다르게 @Component 어노테이션이 없다. 그래서 검색을 해보니 답은 @EnableJpaRepository 어노테이션에 있었다.
@EnableJpaRepository 어노테이션은 Jpa Repository들을 활성화하기 위한 어노테이션인데 스프링에서는 @Configuration을 사용한 설정 클래스에서 @EnableJpaRepositories를 사용해야 하지만 스프링부트는 자동설정이 돼서 생략이 가능하다. 그리고 @EnableJpaRepositories 를 따라가 보면
import 를 통해서 JpaRepositoriesRegistrar 를 임포트 받고 있고 JpaRepositoriesRegistrar 는 이름만 봐도 JpaRepository를 빈으로 등록하는 역할을 한다는 것을 추측할 수 있다. 또한 RepositoryBeanDefinitionRegistrarSupport를 상속받고 있다. 이것은 importBeanDefinitionRegistrar의 구현체라고 볼 수 있는데 이 인터페이스는 BeanDefinition을 정의할 수 있는 특수한 형태의 인터페이스다. 여기부터는 metadata로 코드가 작성돼서 봐도 잘 모르겠다.
JpaRepository를 빈으로 등록하지도 않았는데 주입받을 수 있는 이유를 요약하자면