스프링 스터디, #1

박주진·2021년 8월 3일
0

스프링 스터디

목록 보기
1/3

내용은 주로 전문가를 위한 스프링5에 기반한다.

IOC vs DI

  • 책에서는 di를 ioc의 한 형태라고 정의한다. 또한 ioc와 di를 혼용해서 사용하더라도 큰 의미차이는 없다고 한다. 해당 의미에 혼동이 와서 찾아본 결과 좀 다르다고 한다.
  • ioc는 제어의 역전 즉 코드의 흐름의 주체가 바뀌는것. 오히려 DIP가 이런 개념이 적용된 한형태라고 볼수 있다고한다.
  • DIP란 추상화에 의존하라는 것이다. 추상화의 의존 하기위한 기법중 하나로 di가 존재한다.
  • ioc container란 dip가 적용된 모듈의 조립을 도와주는 도구 이다. 이게 스프링 컨테이너라고 볼수 있을거 같다. 하지만 di는 container 없이도 구현이 가능함으로 한 형태라고 보기는 힘들지 않을까?

의존성을 해결하는 방법(dip를 구현한 기법)

  1. di
  • 필요한 객체들을 스스로 생성하는게 아닌 외부로 부터 주입받는 기법이다.
  • 종류
    - 생성자 주입
    - 세터 주입
    - 메서드 호출 주입 (인자로 전달)
    - 인터페이스 주입 (주입할 의존성을 명시하기 위해 인터페이스 사용)
    public interface DpInjectable {
    	public void inject(DiscountPolicy policy)
    }
    
    public class Movie implements DpInjectable {
    	@override	
    	public void inject(DiscountPolicy policy){
        this.policy = policy
        }
    }
  • 어떤 주입방식을 상황에 맞게 써야할까?
    • 생성자
      - 명시적으로 의존성을 표현하기 위해, 불변객체를 만들기위해
    • 세터
      - 필수적인지 명시적인지 알 수 없고 누락으로 인한 비정상 상태로 객체가 생성될 가능성 있음
      - 런타임에 의존성 변경이 필요한경우 유용하다.
      - 저자는 인터페이스에 의존성을 선언하고 나타낼수 있어 가장 좋다고 주장하나 한편으로는 인터페이스에 특정 의존성을 들어내지 않도록 노려해야한다고 주장한다. 왜냐하면 모든 구현체들이 특정한 의존성을 필요하다고 확신을 못하니까.
    • 메서드
      - 해당 메서드에만 의존성이 필요하다면 좋다.
  • 장점
    - 접착코드 감소?
    • 애프리케이션 구성 단순화 (의존성 구현체 변경이 쉬움)?
    • 단일저장소에 공통 의존성관리??
    • 테스트 편의성
    • 좋은 설계 도출 (인터페이스를 정의하고 이를 컨테이너를 사용해 연결함으로 인터페이스 사용 권장?)

2 service locator(책에서 말하는 의존성 룩업과 비슷한듯?)

  • 외부에서 객체에게 의존성을 주입하는게 아닌 service locator에게 의존성을 해결해줄 것을 요청한다.
  public class Movie {

    private String tile
    private Duration runnigTime;
    private Policy discountPolicy

    public Movie( String title, Duration runnigTime) {
    this.title = title;
    this.runnigTime = runnigTime
    this.policy = ServicLocator.discountPolicy();
    }
    
  }
  • 장점
    - 의존성 주입을 지원하는 프레임워크를 사용 못하거나 깊은 호출 계층에 걸쳐 동일한 객체를 계속 전달해야 하는 경우라면 고려해볼수 있음.
  • 단점
    - 의존성이 감쳐져있다. 이는 캡술화 위반이다. 즉 의존성을 이해하기 위해 코드 내부 구현을 이해할 것을 강요한다.
    - 의존성 관련 문제가 컴파일 타임이 아닌 런타임에 발견될 가능성 높음 (생성시 숨겨진 의존성을 해결하지 않았을때)
    - 테스트 하기 힘듬 (service locator 인스턴스 추가 및 삭제 작업 필요)
    - 의존성 대상을 설정하는 시점과 해결되는 시점이 떨어져 있어 코드를 이해하고 디버깅 하기 힘듬

빈생성 방식

  • 기본은 싱글턴 방식
  • 스프링은 문제의 여지가 있는 싱글턴 디자인 패턴을 사용하지 않고도 싱글턴으로 인스턴스를 사용하게 해준다.
  • 싱글톤의 문제
    • 구체 클래스를 직접 사용하여 의존성 증가
    • 인터페이스로 변경 불가
    • 테스하기 어렵다.( 인퍼에스 기반 싱글턴이 아니라면 그리고 static메소드를 mocking 하기 힘듬)
    • 전역상태가 만들어져 아무 객체나 자유롭게 접근하여 수정 가능
    • 싱글톤을 생성자로 넘겨주면 해결안되나?
  • 싱글턴이 적절한 상황
    • 상태가 없는 객체 (동기화 필요 없음으로)
    • 읽기전용 상태를 갖는 공유객체
    • 공유 상태를 갖는 공유 객체 (모두가 공유되어야하는 상태를 지닌 객체)
    • 쓰기 가능 상태를 갖는 대용량 처리 객체 (새 인스턴스 생성이 많은 자원이 소모되거나,객체의 값을 쓰는 일이 적다면 쓰기접근을 빈 상태에서 동기화하는게 많은 인스턴스 생성보다 성능상 이점이 있을수 있음) 어떻게 하지??
  • 싱글턴이 적절지 않은 상황
    - 쓰기 가능한 상태를 갖는 객체 (새로운 인스턴스 생성이 동기화보다 비용이 덜드는 상황인지 고려 필요)
    • private 상태를 갖는 오브젝트??

autowiring

소규모 어프리케이션에서 시간을 절약할 수 있지만 대규모 어플리케이션에서는 유연성이 오히려 떨어진다. 왜냐하면 하나 이상의 동일한 타입의 빈을 관리하기 힘들고 적절하게 자동으로 주입받기 위해서는 byName등을 통해 명시해야하기 때문이다. 이는 더 복잡해지고 문제발생 요지가 많아진다. 와이어링을 명시적으로 정의해서 같은 타입의 인스턴스 관리하도록 권장한다.

아래와 같은 방식이 책의 저자가 권장하는 방식인가?

@Configuration

public class AnnotationConfig {


    @Bean
    public Car car(Engine engine) {
        return new Car(engine);
    } 
    
    @Bean
    public Engine engine(Camshaft camshaft, Crankshaft crankshaft) {
        return new CombustionEngine(camshaft, crankshaft);
    }

    @Bean
    public Camshaft camshaft() {
        return new Camshaft();
    }
    
    @Bean
    public Crankshaft crankshaft() {
        return new Crankshaft();
    }
}

0개의 댓글