DDD 레포지토리 패턴 적용, 멤버 도메인 개발과 테스팅

dropKick·2020년 8월 5일
0

개발 아키텍처


개발은 도메인 -> 레포지토리 -> 서비스 -> 뷰 -> 컨트롤러

Repository

@Component
public @interface Repository {}
  • @Repository
    이 어노테이션이 스프링 빈으로 관리 될 수 있는 이유는, 인터페이스에 @Component가 있기 때문

    • @Component
  • @SpringBootAplication
    하위 모든 파일과 패키지를 컴포넌트 스캔

  • @PersistenceContext
    스프링부트가 의존성을 주입, JPA만 사용한다면 엔티티 매니저 팩토리 만들고 해야하는데
    빈으로 관리되기 때문에 필요 없음

Service

memberRepository

의존성 주입

@Repository // 어노테이션 등록 시 자동으로 스프링 빈으로 관리
public class MemberRepository {

    @PersistencContext
    private final EntityManager em;
    
    public memberRepository(EntityManager em){
    this.em = em;
    }
  • 원래 엔티티 매니저의 경우 직접 주입해줘야 함
@Repository // 어노테이션 등록 시 자동으로 스프링 빈으로 관리
@RequiredArgsConstructor
public class MemberRepository {

    // 의존성 주입 어노테이션
    private final EntityManager em; // 롬복을 통해 생성자 생성
  • Spring Data JPA를 통해 @RequiredArgsConstruct로 주입 가능

memberService

@Autowired
    public void setMemberRepository(MemberRepository memberRepository) { // setter 인젝션
        this.memberRepository = memberRepository;
    }
  • setter 주입의 경우 어플리케이션 로딩 시점에서 값이 바뀔 필요가 없으나
    값이 변경될 가능성이 있음
@RequiredArgsConstructor // 롬복을 통해 생성자 생성
public class MemberService {

    private final MemberRepository memberRepository; // 생성 시점 외 변경할 필요가 없기에 final
  • 롬복을 통해 생성자 주입 사용
@Service
@Transactional(readOnly = true)
// JPA의 모든 로직은 트랜잭션 안에서 실행 되어야 한다.
// readOnly 걸면 조회 최적화, 더티체킹 안하고 뭐 그럼 읽기가 더 많다면 클래스 레벨 트랜잭션 걸어도 됨
@RequiredArgsConstructor // 롬복을 통해 생성자 생성
public class MemberService {

    private final MemberRepository memberRepository; // 생성 시점 외 변경할 필요가 없기에 final

    // 회원 가입
    @Transactional // 읽기 전용 아님
    public Long join(Member member) {
        validateDuplicateMember(member);
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member) {
        List<Member> findMembers = memberRepository.findByName(member.getUsername());
        if (!findMembers.isEmpty()) {
            throw new IllegalStateException("이미 존재 하는 회원");
        }
    }

    // 회원 전체 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

    // 회원 단건 조회
    public Member findOne(Long memberId) {
        return memberRepository.findOne(memberId);
    }
}
  • @Transactional
    모든 JPA는 트랜잭션 안에서 실행 되어야 함
  • readOnly
    읽기 전용은 JPA가 알아서 최적화 해줌
  • 중복 방지 메소드
    중복 방지를 코드 단에서 구현하더라도 멀티 스레드 환경(WAS 여러개 등)에서 동시 접근하는 등의 문제가 발생할 수 있음
    따라서 DB단에서도 유니크 제약조건을 통해 데이터 중복을 방지해야 함

0개의 댓글