본문 바로가기
Learning-log/Spring & JPA

(스프링 핵심 원리 - 기본편) 3-(7)좋은 객체 지향 설계의 5가지 원칙 적용, (8)IoC, DI, 그리고 컨테이너, (9) 스프링으로 전환하기

by why제곱 2023. 4. 1.

- 좋은 객체 지향 설계의 5가지 원칙 적용

어떻게 적용됐는지 알아보자

  • SRP  : 한 클래스는 하나의 책임만 가져야 한다
    • 클라이언트 객체는 기존에 직접 구현 객체를 생성, 연결, 실행하는 책임을 모두 가지고 있었음
    • SRP 단일 책임 원칙을 따를 수 있도록 관심사를 분리함
    • 구현 객체를 생성하고 연결하는 책임은 AppConfig가 담당하도록 함
    • => 클라이언트 객체는 실행하는 책임만 담당하게 됨.
  • DIP 의존관계 역전 원칙 : 프로그래머는 추상화에 의존해야지 구체화에 의존하면 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나.
    • 새로운 할인 정책을 적용하려면 클라이언트도 함께 변경해야 했음.
      • 기존 클라이언트 코드(OrderServiceImpl)는 DiscountPolicy 추상화 인터페이스에만 의존하는 것 같아 보였지만 FixDiscountPolicy 구체화 구현 클래스에도 함께 의존했음.
      • 그래서 할인정책을 변경하려면 클라이언트 코드의 구체화 구현클래스 부분도 함께 수정해줬어야 했음
    • 하지만 구체화 구현 객체 부분을 없애버리면 인터페이스 만으로는 아무것도 실행할 수가 없음
    • AppConfig가 FixDiscountPolicy 객체 인스턴스를 클라이언트 코드 대신 생성해서 클라이언트 코드에 의존관계를 주입함으로써 문제 해결
  • OCP:  소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀있어야 한다.
    • 다형성을 사용하고 클라이언트가 DIP를 지킴
    • 애플리케이션을 사용영역과 구성영역으로 나눔
    • AppConfig가 의존관계를 변경하고 이를 클라이언트코드에 주입하기 때문에 클라이언트 코드는 어떤 코드도 변경하지 않아도 됐음
    • 소프트웨어 요소를 새롭게 확장해도 사용 영역은 변경에 닫혀 있음.

 

 

-  IoC, DI, 그리고 컨테이너

  • 제어의 역전(Inversion of Control) 
    • 스프링에만 국한된 단어는 아님
    • 보통 개발자가 원하는 대로 객체를 생성, 호출, 접 컨트롤하고 제어하는 형태로 개발을 하는데 개발자가 호출하는 게 아니라 프레임워크 같은 것이 내 코드를 대신 호출해 주는 것을 말함
    • 제어권이 뒤바뀐다고 해서 제어의 역전이라고 부름.
    • 기존 프로그램은 클라이언트 구현 객체가 스스로 필요한 서버 구현 객체를 생성하고, 연결하고 ,실행했음. 즉 구현 객체가 프로그램의 제어 흐름을 스스로 조종했음
    • 반면 AppConfig가 등장하면서 구현 객체는 자신의 로직을 실행하는 역할만 담당. 프로그램 제어 흐름은 이제 AppConfig가 가져감.
    • => 프로그램에 대한 제어 흐름 권한은 AppConfig에 있음
    • 프레임워크 vs 라이브러리
      • 프레임워크 : 내가 작성한 코드를 제어하고 대신 실행(JUnit)
      • 라이브러리 : 내가 작성한 코드가 직접 제어 흐름을 담당 ( Java객체를 xml로 바꾸거나 Json으로 바꾸는 경우)
    • 의존관계 주입
      • OrderServiceImpl은 DiscountPolicy 인터페이스에 의존. 실제 어떤 구현객체가 사용될 지는 이제 모름
      • 의존관계는 정적인 클래스 의존관계와 실행 시점에서 결정되는 동적인 객체 의존관계를 분리해서 생각해야 함.
      • 정적인 클래스 의존 관계
        • 클래스가 사용하는 import코드를 보고 의존관계 판단 가능
        • 애플리케이션을 실행하지 않아도 분석 가능
      • 동적인 객체 인스턴스 의존관계
        • 애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계
      • 의존성주입을 사용하면 정적인 클래스 의존관계를 변경하지 않고(클래스 다이어그램이 변경되지 않고)(애플리케이션 코드에 손대지 않고), 동적인 객체 인스턴스 의존관계를 쉽게 변경 가능
    • IoC 컨테이너, DI컨테이너
      • AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 말함.
      • 의존관계 주입에 초점을 맞추어 최근에는 주로 DI컨테이너를 사용
      • 어셈블러, 오브젝트 팩토리 등으로도 불림

 

 

- 스프링으로 전환하기

  • AppConfig 스프링 기반으로 변경하기
    • class이름 위에 '@Configuration' import가 ' org.springframework.context.annotation.Configuration' 이 맞는지 확인할 것 
      • application의 설정정보, 구성정보임을 표기하는 것.
    • 각 메서드 위에 '@Bean' 붙이기
      •  Bean이라고 붙이는 순간 SpringContainer에 등록 됨.

 

  • 위에서 설정해놓은게 실행될 때도 스프링을 사용할 수 있도록 OrderApp부분 수정해보자.

  • 스프링은 'ApplicationContext'로 시작해서 AppConfig에 있는 환경설정 정보를 가지고 @Bean이 붙은 메서드들을 스프링 컨테이너에 생성된 객체들을 넣어서 관리 해줌.
  • 원하는 객체를 찾을 때도 이 'ApplicationContext' 타입으로 선언된 변수에 저장된 객체를 통해 원하는 객체를 찾아 옴.\
  • 이 때 name은 컨테이너 내에 등록된 메서드 이름으로 원하는 객체를 찾기 위한 수단. 두번째 매개변수는 반환될 타입을 의미함
  • 위와 같이 수정하고 실행해보면 아래와 같이 @Bean으로 등록한 메서드이름들이 등록됐음을 확인할 수 있음.

 

  • ApplicationContext 를 스프링 컨테이너라 함
  • 이제는 스프링 컨테이너를 통해 객체 생성, DI를 함
  • 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 사용하고 여기서 @Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록
  • @Bean이 붙은 메서드 이름을 스프링 빈의 이름으로 사용함. 또는 @Bean(name ="임의지정name")으로 바꿀 수도 있지만 관례상 메서드 이름 그대로 사용하는 것 권장 
  • 스프링 컨테이너를 통해서 필요한 객체를 찾으며 스프링 빈(객체)를 찾는 방법은 'applicationContext.getBean()' 메서드를 활용