결론부터 말하면 spring-data-jpa의 JpaRepository를 상속받아 사용 시 의존성 주입 및 빈등록을 위해 @Repository 어노테이션을 사용할 필요가 없다.
스프링 어플리케이션은 동작시 @ComponentScan 어노테이션을 통해 코드의 컴포넌트를 읽어 싱글톤 패턴으로 빈을 컨테이너에 등록한다.
그래서 우리는 개발을 할때 @Controller, @Service, @Repository 같은 어노테이션을 활용해 의존성 주입을 위한 빈 등록을 해준다.
@Repository의 사용
public interface TestRepository {
Long 회원가입();
User 회원조회();
User 회원수정();
void 회원삭제();
}
@Repository
public class TestRepositoryImpl implements TestRepository{
@Override
public Long 회원가입() {
return null;
}
@Override
public User 회원조회() {
return null;
}
@Override
public User 회원수정() {
return null;
}
@Override
public void 회원삭제() {
}
}
위와같이 인터페이스를 정의하고 클래스로 그 구현체를 만들어 사용한다.
@Test
void repositoryBeanDefinitionTest() {
for(String s : df.getBeanDefinitionNames()){
if(s.contains("Repository")) System.out.println(s);
}
}
위 테스트 코드를 스프링부트 통합테스트를 통해 실행해주면
와 같이 정상적으로 TestRepositoryImpl이 빈으로 등록되어 출력되는걸 확인할 수 있다.
만약 TestRepositoryImpl에 @Repository를 생략하게되면 빈등록이 되지 않아 의존성 주입을 할 수 없게된다.
JpaRepository를 상속받은 리포지토리는
public interface TestRepository extends JpaRepository<User, Long> {
}
이런형식으로 된 코드를 확인할 수 있다.
스프링 컨테이너 및 빈등록, 의존성 주입 등을 공부하며 돌아보니, 여기에는 왜 @Repository 어노테이션이 없어도 의존성 주입이 되는거지? 라는 의문점이 들었다.
위의 코드를 테스트 돌려보면 아래와같이 빈 등록이 정상적으로 되어있는것을 확인할 수 있다.
여기서 든 생각은 JpaRepository 인터페이스를 상속하면 자동으로 빈 주입이 되는것인가? 라는 생각이 문득 들었다.
JpaRepository 코드를 뜯어보니
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
@NoRepositoryBean이라는 어노테이션을 확인하였고, 검색을 통해 찾아본 결과
Repository 인터페이스를 상속받았기 때문에 실제 빈을 만들지 않도록 하기 위하여 사용되고,
실제 사용되는 Repository가 아님을 표시하는것 이였습니다.
그럼 실제 빈등록은 어디서 이루어 질까?
spring-data-jpa의 리포지토리 빈 등록은 @EnableJpaRepositories 어노테이션에서 이루어 집니다.
SpringBoot에서는 자동 설정되어 생략해도 되지만, 원리를 파악해보기 위해 코드를 뜯어보겠습니다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(JpaRepositoriesRegistrar.class)
public @interface EnableJpaRepositories
위 코드의 5번째 라인을 보면 JpaRepositoriesRegistrar.class가 임포트 되어있는것을 확인할 수 있습니다.
여기에서 실제로 JpaRepository를 상속받은 repository 인터페이스를 빈으로 등록해주는 역활을 합니다.
여기에서 실제로 JpaRepository를 상속받은 repository 인터페이스를 빈으로 등록해주는 역활을 합니다.
구체적으로 어떤 클래스의 메소드에서 진행되는지 힌트를 받을 수 있을까요..?