MenuController 생성자로 MenuService의 객체를 전달 받고 있다.
이처럼 생성자를 통해서 어떤 클래스의 객체를 전달 받는 것을 ‘의존성 주입’ 이라고 한다.
생성자의 파라미터로 객체를 전달하는 것을 외부에서 객체를 주입한다라고 표현을 하는 것이다.
그렇다면 여기서 의미하는 객체를 주입해주는 ‘외부’는 무엇일까?
바로 CafeClient 클래스가 MenuController의 생성자 파라미터로 menuService를 전달하고 있기 때문에 객체를 주입해주는 외부가 된다.
클래스의 생성자로 객체를 전달 받는 코드가 있다면 ‘아, 객체를 외부에서 주입 받고 있구나. 의존성 주입이 이루어 지고 있구나’ 라고 생각할 수 있다.
우리가 의존성 주입을 사용할 때, 항상 염두에 두어야 하는 부분이 한가지 있다.
그것은 바로 현재의 클래스 내부에서 외부 클래스의 객체를 생성하기 위한 new
키워드를 쓸지 말지 여부를 결정하는 것이다.
일반적으로 Java에서 new 키워드를 사용해서 객체를 생성하는데, Reflection이라는 기법을 이용해서 Runtime시에 객체를 동적으로 생성할 수 있는 방법이 있다는 사실도 있다.
애플리케이션 코드 내부에서 직접적으로 new
키워드를 사용할 경우 객체지향 설계의 관점에서 중요한 문제가 발생할 수 있다.
new
키워드를 사용해서 객체를 생성하게 되면 참조 할 클래스가 바뀌게 될 경우, 이 클래스를 사용하는 모든 클래스들을 수정할 수 밖에 없다.
이처럼 new 키워드를 사용해서 의존 객체를 생성할 때, 클래스들 간에 강하게 결합(Tight Coupling)되어 있다라고 한다.
결론적으로 의존성 주입을 하더라도 의존성 주입의 혜택을 보기 위해서는 클래스들 간의 강한 결합은 피하는 것이 좋다.
애플리케이션의 요구사항은 언제든 변할 수 있기 때문에 코드를 작성할 때, ‘이렇게 작성해 놓으면 나중에 또 수정이 필요한 부분이 뭐가 있을까?’ 라는 생각은 한번 쯤 해보는게 좋다고 생각합니다.
어떤 클래스가 인터페이스 같이 일반화된 구성 요소에 의존하고 있을 때, 클래스들 간에 느슨하게 결합(Loose Coupling)되어 있다고 한다.
인터페이스 타입의 변수에 그 인터페이스의 구현 객체를 할당할 수 있는데 이를 업캐스팅(Upcasting)이라고 한다.
업캐스팅을 통한 의존성 주입으로 인해 느슨한 결합 관계를 유지할 수 있게 된다.
클래스들 간의 관계를 느슨하게 만들기 위해서는 new
키워드를 사용하지 않아야 되는데, 이전에 객체를 생성하기위해 new
를 사용한 적이 있는 상황이다.
이 new 키워드는 어떻게하면 제거하고 의존 관계를 느슨하게 만들 수 있을까?
Spring이 대신 해준다.
Config
클래스에서 객체 생성을 정의해 두면 이 객체를 애플리케이션 코드에서 사용하게 된다.
한마디로 Config
클래스에 정의해둔 객체를 Spring의 도움을 받아서 다른 클래스에게 제공을 하는 것이다.
이처럼 Spring 기반의 애플리케이션에서는 Spring이 의존 객체들을 주입해주기 때문에 애플리케이션 코드를 유연하게 구성할 수 있다.
애플리케이션 흐름의 주도권이 사용자에게 있지 않고, Framework이나 서블릿 컨테이너 등 외부에 있는 것 즉, 흐름의 주도권이 뒤바뀐 것을 IoC(Inversion of Control)라고 한다.
DI(Dependency Injection)는 IoC 개념을 조금 구체화 시킨 것으로 객체 간의 관계를 느슨하게 해준다.
클래스 내부에서 다른 클래스의 객체를 생성하게 되면 두 클래스 간에 의존 관계가 성립하게 된다.
클래스 내부에서 new를 사용해 참조할 클래스의 객체를 직접 생성하지 않고, 생성자 등을 통해 외부에서 다른 클래스의 객체를 전달 받고 있다면 의존성 주입이 이루어 지고 있는 것이다.
new 키워드를 사용하여 객체를 생성할 때, 클래스 간에 강하게 결합(Tight Coupling)되어 있다고 한다.
어떤 클래스가 인터페이스 같이 일반화 된 구성 요소에 의존하고 있을 때, 클래스들 간에 느슨하게 결합(Loose Coupling)되어 있다고 한다.
객체들 간의 느슨한 결합은 요구 사항의 변경에 유연하게 대처할 수 있도록 해준다.
의존성 주입(DI)은 클래스들 간의 강한 결합을 느슨한 결합으로 만들어준다.
Spring에서는 애플리케이션 코드에서 이루어지는 의존성 주입(DI)을 Spring에서 대신 해준다.