본문 바로가기
Spring

[SpringBoot] DI 생성자 주입

by noddu 2023. 10. 26.
728x90
반응형

 

 

생성자 주입 전

 

OrderServiceImpl.java

public class OrderServiceImpl implements OrderService{

    MemberRepository memberRepository = new MemoryMemberRepository();	// DIP 위반!
    
    @Override
    public Order createOrder(Long memberId) {
        Member orderMember = memberRepository.findById(memberId);
        
        ...
    }
}

 

OrderServiceImpl이 MemberRepository(인터페이스) 뿐만 아니라 구현체인 MemoryMemberRepository에도 의존하고 있습니다.

만약 구현체를 MemoryMemberRepository에서 다른 구현체로 변경할 때면 OrderServiceImpl클래스에서도 변경해야 하기 때문에 OCP도 위반하게 됩니다.

 

 

 

생성자 주입 후

 

OrderServiceImpl.java

public class OrderServiceImpl implements OrderService{

    MemberRepository memberRepository;

    public OrderServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member orderMember = memberRepository.findById(memberId);
        
	...
    }
}

이렇게 생성자를 통해서 구현체를 주입받게 하면 OrderServiceImpl은 구현체를 알 수 없고,

MemoryMemberRepository(구현체)가 아닌 MemberRepository 인터페이스에만 의존하게 됩니다.

 

이렇게 OrderServiceImpl에서 의존관계를 외부로부터 주입받는걸 DI(의존관계 주입 or 의존성 주입)라고 합니다.

위 코드는 그 중에서도 생성자 주입입니다.

 

 

AppConfig.java

public class AppConfig {
    public OrderService orderService() {
        return new OrderServiceImpl(
                new MemoryMemberRepository(),
        );
    }
}

AppConfig가 실제 구현체를 생성하도록 했습니다.

orderService() -> new OrderServiceImpl

-> OrderServiceImpl.java의 생성자 memberRepository 파라미터에  MemoryMemberRepository가 주입됩니다.

 

 

테스트

 

class OrderServiceTest {
    MemberService memberService;
    OrderService orderService;

    @BeforeEach // 테스트 시작하기 전에 실행되는 애노테이션
    public void beforeEach(){
        AppConfig appConfig = new AppConfig();   // AppConfig 객체 생성
        orderService = appConfig.orderService();	// 여기서 실행해서 의존성 주입!
    }

    @Test
    @DisplayName("오더 서비스 테스트")
    void orderTest(){
        long memberId = 1L;
        Member member = new Member(memberId, "홍길동", Grade.BRONZE);

        memberService.join(member);
        Order order = orderService.createOrder(memberId, "itemA", 10000);

        ...
    }
}

orderService.createOrder()는 OrderServiceImpl.java처럼 memberRepository의 함수 등 실행해야 하기 때문에 구현체가 필요합니다. (구현체가 주입되지 않으면 NPE가 발생합니다)

 

생성자 주입으로 MemoryRepository가 주입되어서 위 테스트에서는 성공합니다

 

 

결과

 

OrderServiceImpl은 인터페이스인  memberRepository에만 의존하며 구현체를 몰라도 됩니다. DIP!

구현체인 MemoryMemberRepository말고 다른 구현체로 변경해도 OrderServiceImpl에서는 바꿀 코드가 없습니다. OCP!

반응형