p.111 ~ 128
스프링의 기본적인 동작 원리가 모두 IoC 방식이라고 할 수 있지만, 스프링이 다른 프레임워크와 차별화돼서 제공해주는 기능은 의존관계 주입이라는 새로운 용어를 사용할 때 분명하게 드러난다.
그래서 초기에는 IoC컨테이너라고 불리던 스프링이 지금은 의존관계 주입 컨테이너, DI 컨테이너라고 더 많이 불린다고 한다.
제어의 역전은 쉽게 생각해서 내가 작성한 코드가 직접 제어의 흐름을 담당하지 않고, 그 제어권을 프레임워크가 담당하는 것이라고 이해하면 되는데 라이브러리와 프레임워크의 차이도 그렇게 이해하면 될 것 같다.
제어권을 코드가 가지고 있다면 라이브러리를 사용한 것, 제어권을 가지고 있지 않다면 프레임워크
스프링 컨테이너는 빈이 등록되는 컨테이너라고 생각하면 되는데, 빈은 어노테이션으로 자동 등록되고
거기서 ApplicationContext(BeanFactory)를 통해 빈을 꺼내서 사용할 수 있다.
이번 주 내내 프로젝트를 구현하면서, 인터페이스의 구현체를 만드는 것이 의미가 있는지 오히려 파일 자체를 하나 더 만들게 되니까 번거로운 작업이 아닌가 고민했다. 뭐 인터페이스를 상속받아서 구현하는 클래스가 다양한 경우(책에서는 N사, D사와 같은 경우)가 있을 수 있다지만, 솔루션을 만드는 경우도 아니라면 더욱 왜 그렇게까지 하는건지 이해가 안되었는데 의존관계가 여기의 실마리였다!
클래스 A가 B에 의존하고 있음을 나타내는 UML 다이어그램이다.
의존한다는 것은 의존대상(B)가 변하면 그것이 A에 영향을 미친다는 것을 뜻한다.
대표적인 예는 A가 B에 정의된 메소드를 호출해서 사용하는 경우다.
만약 B에 새로운 메소드가 추가되거나 기존 메소드가 변경되면 A도 그에 따라서 수정해야 한다.
만약 클래스끼리 직접적인 의존관계가 아닌 클래스와 인터페이스간 의존관계가 있고, 인터페이스를 구현한 클래스를 사용한다면 구현체가 변경되거나 내부의 메소드에 변화가 생겨도 UserDao에는 영향을 주지 않는다.
이렇게 인터페이스에 대해서만 의존관계를 만들어두면 인터페이스 구현 클래스와의 관계는 느슨해지면서 변화에 영향을 덜 받는 상태가 된다. 결합도가 낮다고 설명할 수 있다.
주입이라는 건 외부에서 내부로 무엇인가를 넘겨줘야 하는 것인데, 자바에서 오브젝트에 무엇인가를 넣어준다는 개념은 메소드를 실행하면서 파라미터로 오브젝트의 레퍼런스를 전달해주는 방법뿐이다. 가장 손쉽게 사용할 수 있는 파라미터 전달이 가능한 메소드는 바로 생성자다.(p.116)
DI는 자신이 사용할 오브젝트에 대한 선택과 생성 제어권을 외부로 넘기고 자신은 수동적으로 주입받은 오브젝트를 사용한다는 점에서 IoC의 개념에 잘 들어맞는다. 스프링 컨테이너의 IoC는 주로 의존관계 주입 또는 DI라는 데 초점이 맞춰져 있다. 그래서 스프링을 IoC 컨테이너 외에도 DI 컨테이너 또는 DI 프레임워크라고 부르는 것이다.(p.117)
스프링에서는 의존관계 주입 이외에도 의존관계를 스스로 검색해서 이용하는 의존관계 검색(DL)도 있다.
의존관계 검색이 바로 스프링 컨테이너에서 getBean()을 통해서 빈을 찾아서 오브젝트를 가져오는 방법인데, 테스트 코드등을 작성할 때는 static 메소드인 main 메소드에서는 DI를 이용해서 오브젝트를 주입받을 방법이 없기 때문에 의존관계 검색을 사용해서 오브젝트를 가지고 와야 한다.
DI와 DL의 차이점은, DI를 원하는 오브젝트는 자기 자신도 컨테이너가 관리하는 빈으로 등록되어야 하고
DL의 경우에는 자기 자신은 빈으로 등록되어야 할 필요가 없다는 점이다.
의존관계는 생성자, 수정자(setter), 메소드, 필드를 이용해서 주입이 가능하다.
수정자의 경우, 1개의 파라미터만 가질 수 있지만, 메소드를 통한 주입은 여러 파라미터를 가질 수 있다.
//수정자 메소드를 이용한 DI
public class UserDao {
private ConnectionMaker connectionMaker;
public void setConnectionMaker(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
}