- 객체 자체가 아니라, 외부 (Framework 등)에 의해 객체 의존성이 주입되는 설계 패턴
- 필요로 하는 오브젝트를 스스로 생성하는 것이 아닌,
외부로부터 주입
받는 기법- 필요한 자원을 외부에서 넣어주는게 바로 의존성 주입이다
- Dependency Injection은
IoC 개념이 적용된 결과물
중 하나이다- 의존성을 주입한다는 것을 IoC 적인 행위로 바라볼 수 있지만, IoC와 의존성 주입이 같은 것은 아니다
DI는 DIP를 구현하는 기법중 하나일 뿐 서로 같은 개념이 아니다
- 스프링은 DI라는 방식을 이용하여 모듈간 결합도를 낮추어준다
- 스프링에서의 DI란
Spring IoC Container
가 개발자 대신 정의된 대로Bean
객체를 생성하고의존성을 대신 주입
하는 것을 의미한다- 여기서 IoC란 제어의 역전이라는 말로 사용자가 직접 객체를 생성하고 관리하던 것을, Spring의 IoC Container가 대신 해준다는 말이다
- 개발자가 해야하는 일
- Bean class 작성
- 주입을 위한 설정 (xml파일 기술 또는 @(어노테이션) 기술)
- 의존성 주입을 이용하면 결합도를 낮출 수 있다
- 느슨한 결합이 가능하도록 유도할 수 있게 되고, 이 과정에서 OCP 원칙을 적용할 수 있게 된다
- OCP (Open Closed Principle - 개방 폐쇄 원칙)
- 확장에 대해 열려있고, 수정에 대해서는 닫혀있어야 한다는 원칙
- OCP (Open Closed Principle - 개방 폐쇄 원칙)
- 스프링은 IoC 를 기반으로 동작한다
- IoC를 이용하면
로직 실행과 구현의 분리
가 가능해지며, 구현 간의 전환이 쉬워진다 - 컨테이너가 Bean의 라이프 사이클을 관리하므로, 개발자의 관리 포인트가 줄어든다는 장점이 있다
- IoC에서 사용하는 패턴이 바로 DI이다
- IoC를 이용하면
Spring Framework에서는 Dependency Injection을 3가지 방식으로 지원하고 있다
생성자에 의존성 주입을 받고자 하는 field를 나열하는 방법으로, 권고되는 방법 중 하나이다
장점
- 인스턴스가 생성되었을 때 의존성이 존재하는 것이 보장되기 때문에, 의존성 존재 여부가 보장되고 의존상을
immutable
하게 정의할 수 있다 - 필수적으로 사용해야 하는 레퍼런스 없이는 인스턴스를 만들지 못하도록 강제한다
- Spring 4.3 이상부터는,
생성자가 하나
인 경우 @Autowired를 사용하지 않아도 된다묵시적 생성자 자동 주입
- Circular Dependency (순환 참조) 의존성을 알아차릴 수 있다
- 의존성 대상 field를
final
로 불변 객체를 선언할 수 있다 - Test case 작성 시, 생성자를 통해 의존성 주입이 용이하다
- 인스턴스가 생성되었을 때 의존성이 존재하는 것이 보장되기 때문에, 의존성 존재 여부가 보장되고 의존상을
단점
- 어쩔 수 없는
순환 참조
는 생성자 주입으로 해결하기 어렵다- 이 때 나머지 주입 방법을 사용하도록 하지만, 순환 참조가 발생하지 않도록 하는 것이 중요하다
- 어쩔 수 없는
setter method에 @Autowired annotation을 선언하여 주입하는 방법
장점
- 의존성이
선택적으로 필요
한 경우에 사용 - 생성자에 모든 의존성을 기술하면 과도하게 복잡해질 수 있는 것을 선택적으로 나눠서 주입할 수 있다
- 의존성이
유의할 점
- 주입 받은 의존성의 기본값을 정의할 수 없다면, null 값이 존재할 수 있다
단점
- 의존성 주입 대상 필드에 final로 불변 객체를 선언할 수 없다
member field에 @Autowired annotation을 선언하여 주입하는 방법
장점
- 코드가 간결해진다
단점
- 의존 관계가 눈에 보이지 않아 추상적이고, 이로 인해 의존성 관계가 복잡해질 수 있다
- SRP (Single Responsibility Principle:
단일 책임 원칙
)에 반하는anti-pattern
- Unit test 시 의존성 주입이 용이하지 않다
- 의존성 주입 대상 필드에 final을 선언할 수 없다
결론: 생성자 주입과 setter 주입을 적절히 상황에 맞게 사용하자!