본문 바로가기
Spring

스프링 핵심 원리 기본편 - 챕터 3

by mingutistory 2023. 3. 10.
728x90

Chapter 3. 스프링 핵심원리 이해2 - 객체 지향 원리 적용

유연성 없는 이전 예제를 통해서 스프링 컨테이너의 중요성을 이해함

 

서비스에서 인터페이스를 도입하는 것은 장단점이 있다.

구현체를 변경할 일이 전혀 없다면 인터페이스를 도입하는 것도 비용이 될 수 있다. 변하냐, 변하지 않느냐에 대한 부분에 따라서 결정한다.

https://www.inflearn.com/questions/296430/memberservice-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EA%B5%AC%ED%98%84-%EC%9D%B4%EC%9C%A0

 

MemberService 인터페이스 구현 이유 - 인프런 | 질문 & 답변

영한선생님 궁금한게 있습니다. MemberRepository는 메모리에도 저장할 수 있고, 디비에도 저장할 수 있기에 인터페이스로 구현 후에 구체화 하여 클래스를 구현하는 것 까지는 이해가 되는데 MemberSe

www.inflearn.com

 

관심사의 분리

실제 실행되는 객체들은 본인의 역할들만 수행하고 어떤 구현체가 할당될지는 객체가 아니라 다른 곳에서 해야함.

 

AppConfig

객체를 생성하고 연결하는 역할(AppConfig)와 실행하는 역할이 명확이 분리되었다.

// 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
    }

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

// 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)한다.
public class OrderServiceImpl implements OrderService {

    // 의존 관계를 마치 외부에서 주입해주는 것과 같아 보임(의존 관계 주입 DI - Dependency Injection)
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

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

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        ....
    }
}

 

OrderServiceImpl의 생성자를 통해서 어떤 구현 객체가 주입될지는 외부(AppConfig)에 의해서 결정된다.

의존관계에 대한 고민은 외부실행에만 집중 한다.

 

 

Q. 왜 테스트 코드에서 beforeEach에 new AppConfig()를 해줄까?

A. 매 테스트마다 데이터를 초기화 하기 위함. 각 테스트를 독립적으로 실행하기 위해서임.

 

Q, 이렇게 쓰면 안될까요?

A. MemberRepository에 대한 의존성을 외부에서 주입 받는 건 맞지만 AppConfig에 대한 의존성이 생김.

class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository = AppConfig.memberRepository();
}

 

IoC, DI 그리고 컨테이너

제어의 역전

구현 객체가 스스로 필요한 구현 객체를 생성하는 것이 아니라 자신의 로직을 실행하는 역할만 담당하고 제어 흐름은외부(AppConfig)에서 가져가는 것. 

호출하는 제어권을 넘기는 것.

 

프레임워크 vs 라이브러리

프레임워크: 내가 작성한 코드를 제어하고, 대신 실행하는 것 (Junit)

라이브러리: 내가 작성한 코드가 제어의 흐름을 담당함 

 

의존관계 주입 DI

의존 관계는 정적인 클래스 의존 관계와, 실행 시점에 결정되는 동적인 객체 (인스턴스) 의존 관계를 분리해서 생각해야 함.

 

정적인 클래스 의존 관계

소스 코드를 보고 바로 알 수 있음. 

애플리케이션을 실행하지 않아도 import 코드만 보고 판단이 가능하다.

 

동적인 객체 인스턴스 의존 관계

애플리케이션 실행 시점에 실제 생성된 객체의 참조가 연결된 의존 관계다.

 

애플리케이션이 시작되는 시점외부에서 구현 객체를 생성하여 실제 의존 관계가 연결 되게 하는 것

객체 인스턴스를 생성, 참조값을 전달하여 연결한다.

정적인 클래스들을 변경하지 않고(=> 클라이언트 코드를 변경하지 않고)  동적인 인스턴스를 변경 할 수 있다.

 

IoC 컨테이너, DI 컨테이너

AppConfig처럼 객체를 생성하고 관리하면서 의존 관계를 연결해주는 것

의존 관계의 주입을 대신 해주는 것

 

스프링으로 전환하기

ApplicationContext = 스프링 컨테이너

스프링 컨테이너는 @Configuration 어노테이션을 가진 AppConfig를 설정 정보로 사용.

@Bean이라 적힌 메서드를 모두 스프링 컨테이너에 등록하여 스프링 빈으로 사용한다.

300x250

댓글