스프링 핵심원리

byeol·2022년 11월 18일
0

🙂 김영한님의 인프런 강좌 스프링의 핵심원리를 듣고
복습하면서 정리

2. 스프링의 핵심 원리 이해 1-예제 만들기

1) 프로젝트 생성

2) 비즈니스 요구사항과 설계

전체적인 순서

  • 1) 먼저 비즈니스 요구사항을 설계
    • 회원
      가입, 조회
      두가지 등급 VIP, 일반
      자체 DB구축, 외부 시스템과 연동 (미확정)
    • 주문과 할인
      회원은 상품을 주문
      회원 등급제에 따른 할인정책
      할인 정책은 모든 VIP 1000원 고정 할인(나중에 변경)
      할인정책 변경 가능성 높음
  • 2) 도메인을 설계할 때 도메인 협력 관계, 클래스 다이어그램, 객체 다이어 그램을 만든다.
  • 3) 코드로 각각을 개발

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

"이제 고정금액 1000원이 아니라 회원 등급이 VIP인 경우 구입 금액의 10%를 할인하는 정책을 적용해주세요."

오마이갓...
인터페이스를 통해서 역할과 구현을 분리했지만
이건 객체지향 설계를 지키고 있는 것은 아니다!

그래도 일단 RateDiscountPolicy 클래스를 만든다.

public class OrderServiceImpl implements OrderService {
// private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
   private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
}

이는 DIP를 위반한다. OrderServiceImpl는 역할과 구현체 모두에 의존한다.
또한 OCP도 위반한다. RateDiscountPolicy 클래스를 추가하였는데 수정할 부분이 너무 많다. 클라이언트 코드에 영향을 많이 준다

객체를 직접 만드는 클래스를 하나 따로 빼자->즉 서비스 코드에서 객체를 생성하지 않고 외부에서 객체를 생성하도록 클래스를 구현하는 것 -> main,OrderServiceImpl,MemberServiceImpl 등의 클라이언트는 외부에서 객체를 만들고 이를 서비스 코드에 주입하는 방법으로 객체지향 설계를 완성한다. -> 스프링이 등장하게 된 계기

✔️ 구현 객체를 생성하고, 연결하는 책임을 가진 별도의 클래스를 설정한다.

-> 다시 리펙토링하는 과정을 거치자. 역할에 따른 구현이 제대로 보이지 않음

public MemberService memberService() {
       return new MemberServiceImpl(memberRepository());
  }
public OrderService orderService() {
       return new OrderServiceImpl(
                     memberRepository(),
                     discountPolicy());
  }
public MemberRepository memberRepository() {
       return new MemoryMemberRepository();
  }
public DiscountPolicy discountPolicy() {
       return new FixDiscountPolicy();
  }
}

✔️ "클라이언트 코드에 외부 클래스로부터 생성자 주입을 받기 위한 생성자를 생성"

✔️ Test

IoC, DI 그리고 컨테이너

따라서 아래와 같은 구조가 완성되었다.

이 구조를 보면

프로그램의 제어 흐름은 AppConfig가 담당한다. 기존에 클라이언트가 구현객체를 생성하고 실행했다면 이를 분리해서 클라이언트는 실행만 담당하고 외부에서는 객체를 생성한다. 제어의 권한이 이제 외부로 넘어간 것이다. 이를 제어의 역전(IoC : Inversion of Control)이라고 한다.

우리가 클라이언트 코드만 보고서 알 수 있는 것은 어떤 인터페이스, 역할에 의존하고 있다는 것만 알 수 있다. 실제 어떤 구현체가 작동하는지 알 수 없다. 이를 정적인 클래스 의존관계라고 한다.
하지만 실제 어떤 구현체가 작동하는지 알려면 우리는 코드를 실행해야 한다. 이를 실행 시점에 결정되는 동적인 객체 의존관계라고 한다.
이렇게 실행 시점에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것을 의존관계 주입이라고 한다.

이렇게 AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것은 IoC컨테이너 또는 DI컨테이너라고 부른다.

스프링의 등장

객체를 직접 만드는 클래스가 아닌 스프링 컨테이너를 이용하도록 하자
-> 그러기 위해서는 직접 객체를 생성하는 외부 클래스에 <@Configuration : 싱글톤을 유지하고 스프링 컨테이너에게 설정 정보를 제공, @Bean : 각 메소드들을 스프링 컨테이너에 등록하라고 알려주는 것> 선언한다.
-> 서비스 코드는 ApplicationContext를 통해서 스프링 컨테이너를 만들고 거기에 등록되어져 있는 스프링 빈을 사용한다.

사람들은 정말 똑똑하다
일단 ApplicationContext는 스프링 컨테이너 자체이다.
그 이전에 우리는 순수 자바코드로 클래스를 만들어 생성자를 만드는 객체를 호출해서 사용하여 DI를 했지만 이제는 스프링 컨테이너를 이용한다.

스프링 컨테이너는

  • @Configuration이 붙은 AppConfig.class를 설정 정보로 사용한다.
  • @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체(즉 return값)를 스프링 컨테이너에 등록한다.
  • 이렇게 등록된 객체를 '스프링 빈'이라고 부른다.
  • 이 스프링 빈의 이름은 메서드의 이름이 된다. (memberService, orderService)
  • 객체를 찾을 때 applicationContext.getBean("스프링빈 이름", 스프링빈 타입)을 사용한다.
profile
꾸준하게 Ready, Set, Go!

0개의 댓글