- DDD와 JpaRepository
- JpaRepository를 상속한 인터페이스는 Infrastructure에 있어야 한다
- QueryDsl을 사용하는 경우는 어떻게 해야 할까?
이전에 DDD에 대한 글을 작성했었다.
그와 별개로 Jpa를 사용할 때, 인터페이스를 사용하며 JpaRepository를 상속받게 된다. 이에 대해 정리해보았다.
JpaRepository는 엄연히 외부 라이브러리이다. 따라서 domain 계층에서 이에 대한 의존성을 직접 가지면 안 된다.
DIP 규칙을 위반하게 되면 Repository 구현체를 JPA가 아닌 다른 것으로 변경할 때 문제가 될 수 있다. 따라서 다음과 같이 구성해야 한다.
우선 JpaRepository를 상속받는 인터페이스는 infrastructure 계층에 추가한다.
public interface UserRepositoryImpl extends JpaRepository<User, Long>, UserRepository {
}
이 인터페이스는 UserRepository를 상속받고 있는데, 이것은 domain 계층에 위치한다.
@Repository
public interface UserRepository {
List<User> findAll();
Optional<User> findById(Long id);
User save(User user);
}
이 인터페이스에 작성된 메서드들이 JPA에서 기본 제공되는 메서드이긴 하지만, UserRepository는 그것을 알 수가 없다. 따라서 따로 선언해주어야 한다.
application 계층의 service 클래스에서는 다음과 같이 의존성 주입을 통해 사용한다.
@Service
public class UserService {
private final UserRepository userRepository;
domain 계층의 UserRepository 타입으로 선언했지만, 이것을 infrastructure 계층의 UserRepositoryImpl이 상속받고 있으므로 의존성 주입이 자연스럽게 이루어질 것이다.
DDD를 적용하지 않았던 프로젝트에서 다음과 같이 QueryDsl을 사용했었다.
@Repository
public interface UserRepository extends JpaRepository<User, String>, UserRepositoryCustom {
boolean existsByNickname(String nickname);
boolean existsBySlackId(String slackId);
}
public interface UserRepositoryCustom {
Page<UserResponseDto> searchUsers(String username, String nickname, Pageable pageable);
}
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
private final JPAQueryFactory queryFactory;
public UserRepositoryCustomImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Page<UserResponseDto> searchUsers(String username, String nickname, Pageable pageable) {
/* 구현 내용 생략 */
}
}
UserRepository는 JpaRepository와 UserRepositoryCustom를 구현하고 있다. UserRepositoryCustomImpl이 스프링을 통해 의존성 주입될 것이다.
이 경우에는 어떻게 처리할 수 있을까에 대해 고민해보다 질문을 통해 답변을 받았다.

우선 QueryDsl도 외부 라이브러리 의존성이므로 infrastructure에
UserRepositoryCustom, UserRepositoryCustomImpl을 모두 위치시킨다.
의존성 주입을 통해 타고 들어가서 결론적으로 우리가 application 계층에서 사용하는 UserRepository에서는 JpaRepository의 메서드 뿐만 아니라 QueryDsl을 통해 구현한 메서드도 사용가능하게 될 것이다.
다만 이 경우에도 UserRepository에 메서드들을 선언해 주어야 할 것이다.
굿입니다.