본문 바로가기

개발 독서/토비의 스프링3

[토비의 스프링3] 8-4. 스프링의 기술(1) - IoC/DI

728x90
반응형

'토비의 스프링3' 개발 서적을 읽으며 내용을 정리한 글입니다.

 

8.4 스프링의 기술

  • 스프링에는 POJO 프로그래밍을 쉽게 할 수 있도록 3 가지 가능기술을 지원한다.
    : IoC/DI, AOP, PSA
  • 스프링은 단지 이런 기술을 제공하는 기술 프레임워크가 아니다. 스프링의 진정한 목표는 POJO 기반의 엔터프라이즈 개발을 편리하게 해주는 것이다. 따라서 스프링이 직접 제공하지 않는 기술에 대해서도 가능기술을 적용하여 개발하는 것이 목적과 핵심 가치에 부합한다.

 

제어의 역전(IoC) / 의존관계 주입(DI)

IoC/DI는 스프링의 가장 기본이 되는 기술이자 핵심 개발 원칙이다. 왜 이 원칙이 필요한지 알아보자.

 

왜 두 개의 오브젝트를 분리해서 만들고, 인터페이스를 느슨하게 연결한 뒤, 실제 사용할 대상은 DI를 통해 외부에서 지정하는 것일까?
new 키워드로 생성해서 사용하는 강한 결합을 쓰는 방법보다 나은 점은 무엇일까?

-> 유연한 확장이 가능하게 하기 위해서.

 

개방 폐쇄 원칙으로 설명이 가능하다. (OCP, 객체지향 설계 원칙 중 하나)

  • 개방 폐쇄 원칙 : 확장에는 열려있고, 변경에는 닫혀있다.

예시

  • A->B 의존관계의 오브젝트 구조라고 가정한다.
  • 확장 : B가 자유롭게 변경(A에서 확장)될 수 있음을 의미한다. B가 변경되어도 A는 아무 영향을 받지 않고 그대로 유지 가능하다.
  • B 관점에서는 유연한 확장, A 관점에서는 변경 없이 재사용 가능

 

DI의 활용 방법

  • 핵심기능의 변경 (전략 패턴)
    • 의존하는 대상의 구현을 통째로 바꿀 때 DI를 사용한다.
    • A->B 구조에서 A의 기능 일부를 B(의존 대상)에게 위임했을 때 B의 구현 방식을 통째로 바꾸는 것.
    • 예시
      • 서비스 오브젝트(A)가 사용하는 DAO(B)가 있을 때, DAO의 구현을 JDBC, JPA, 하이버네이트, iBatis 등으로 변경하고 싶다. 실제 의존 대상이 가진 핵심기능을 DI 설정을 통해 변경하면 된다.
  • 핵심기능의 동적인 변경
    • 애플리케이션을 동작하는 중간에 그 의존 대상을 다이나믹하게 변경할 수 있다.
    • (참고) 기본적으로 런타임 시 DI가 되면 그 후로 바뀌지 않는다.
      -> 동적인 방식으로 연결되지만 정적인 관계가 맺어짐
    • 예시
      • 사용자 등급에 따라 다른 DataSource를 사용하게 만들 경우
        DAO->DataSource 의존관계. DAO 하나로 사용자 등급이 VIP면 좀 더 속도가 빠른 DB를 이용할 수 있는 DataSource를 사용하도록 DI를 동적으로 바꿔주고자 할 때 선택적으로 DataSource를 바꿔주는 기법을 적용할 수 있다.
      • 사용자 별 독립적인 상태 정보를 저장하고싶은 경우
        위 예시처럼 핵심기능이 바뀐다기 보다는 기능은 같지만 독립적인 상태 정보를 저장할 수 있는 자신만의 오브젝트를 가질 수 있다. 매번 요청 있을 때마다 새로운 요청이 필요한 경우 new이용해 새로 만들겠지만 한번 로그인한 사용자에게 같은 오브젝트가 적용되어야 한다면 DI 방식이 편리하다.
    • 사용 기법 : 다이나믹 라우팅 프록시, 프록시 오브젝트 기법
  • 부가기능의 추가 (데코레이션 패턴)
    • 핵심 기능은 그대로 둔 채 부가 기능을 추가하는 것.
    • 인터페이스를 두고 사용하게 하고, 실제 사용할 오브젝트는 외부에서 주입하는 DI를 적용하여 사용한다. 핵심 기능과 클라이언트 코드에는 전혀 영향을 주지않으면서 부가적인 기능은 얼마든지 추가할 수 있다.
    • 예시
      • 트랜잭션 기능
        핵심기능은 그대로 두고 결과나 전달 파라미터 조작, 로깅, 보안 처리 같은 부가 작업 수행
      • 이벤트 발생 작업 (부가작업 추가)
    • 부가기능의 추가를 더 많은 대상으로 일반화 한다면 AOP가 된다.
    • DI의 핵심 원칙인 OCP가 말하는 확장에 열려 있다는 것에도 들어맞는 내용이다.
  • 인터페이스의 변경 (어댑터 패턴)
    • 클라이언트가 사용하는 인터페이스와 실제 오브젝트 사이에 인터페이스가 일치하지 않는 경우에 사용한다.
    • 예시
      • 220V 전기를 원하는 9V, 6V, 12V식으로 바꿔주는 어댑터
        A->B(위임)->C 로 구성한다. A는 B의 인터페이스를 이용하여 C의 인터페이스를 이용하고자 하는 경우이다.
    • 이를 좀 더 일반화 한다면 PSA(일관성 있는 서비스 추상화)가 그 방법이다.
      : 아예 인터페이스가 다른 다양한 구현을 같은 방식으로 사용하도록, 중간에 어댑터 역할 해주는 레이어를 추가하는 방법
  • 프록시
    • 지연 로딩을 적용할 경우
    • 원격 오브젝트 호출 시 로컬 존재하는 오브젝트처럼 사용할 수 있도록 원격 프록시를 적용할 경우
  • 템플릿과 콜백
    • 반복적으로 등장하지만 항상 공정적인 작업 흐름과 자주 바뀌는 핵심 부분을 분리해서 템플릿과 콜백으로 만들고 DI 원리를 응용해 적용하는 것이다.
    • 콜백을 템플릿에 주입하는 방식 -> DI 원리를 응용한 것
    • 콜백 : 얼마든지 만들어서 사용할 수 있음. 개방을 통한 유연한 확장
      템플릿 : 계속 재사용 가능. 폐쇄 원칙 적용
  • 싱글톤과 오브젝트 스코프
    • DI 대상 오브젝트를 DI컨테이너가 관리하여 오브젝트의 생명주기(스코프)를 관리한다.
    • 대표적으로 싱글톤
      • 싱글톤은 상태를 갖지 않는 오브젝트이다.
      • 하나 또는 소수의 오브젝트가 수많은 클라이언트를 상대로 고성능 서비스를 제공하는 방식을 원할 때 사용한다.
      • 전통적인 싱글톤 패턴은 오브젝트가 많은 제약을 가해서 만들어지기 때문에 권하지 않는다. 컨테이너가 요브젝트를 관리하는 IoC 방식이 유용하다.
      • 스프링의 DI는 기본적으로 싱글톤으로 오브젝트를 만들어서 사용하게 한다. 컨테이너가 알아서 싱글톤을 만들고 관리하기 때문에 클래스 자체는 싱글톤을 고려하지 않고 자유롭게 설계하는 장점이 있다.
    • 임의 생명주기를 갖는 오브젝트가 필요한 경우 개발자가 오브젝트 만들어 DI에 적용하는 것도 가능하다.
  • 테스트
    • 다른 오브젝트와의 사이에서 일어나는 일을 테스트를 위해 조작할 수 있도록 만드는 것이다.
    • 예시
      • 복잡한 테스트 데이터가 준비되어 있어야 원하는 결과를 가져오는 DAO를 사용하는 오브젝트가 있을 경우, DAO가 완벽히 작성되어야 하고 테스트 데이터까지 완벽 준비되어 있어야 원하는 결과를 얻을 수 있다. 이러면 테스트 때문에 배보다 배꼽이 더 커지는 상황이다.
    • 스텁, 목 오브젝트 같은 테스트 대역을 활용한다. DI를 사용한 테스트 기법을 사용하여 테스트를 독립적으로 진행할 수 있다.
728x90
반응형