DI Container의 결합성과 테스트 용이성
- DI Framework의 핵심 아이디어는 관리되는 Class가 DI Container에 의존성이 없어야 한다. 필요한 의존성을 전달하면 독립적으로 Instance화 할 수 있는 단순 POJO여야한다.
- DI Container 없이도 Unit Test에서 Instance화 시킬 수 있고, 각각 나누어서 테스트도 할 수 있다.
- Container의 결합성이 없다면 관리하거나 관리하지 않는 Class를 사용할 수 있고, 심지어 다른 DI Container로 전환할 수 있다.
DI(Dependent Injection) Field : 의존성 주입 중 필드방식
변수 선언부에 @Autowired Annotation을 넣으면 끝나는 간편한 방법이면서도 읽기도 장점이 있지만 단점들이 더 많다.
순환 의존성
- 우선 A는 자신이 불리면 B를 부른다고 하고 B는 자신이 불리면 A를 부른다고 가정해보자
- A를 불렀다 A가 무엇을 하겠는가? 그렇다 B를 부른다 그러면 불린 B는 무엇을할까? 자신이 할일인 A를 부르게 된다. 그럼 불린 A는 또 무엇을 할까?
다시 처음으로 돌아가 A는 B를 부르게 된다. 이렇게 순환 하면서 참조 하는 경우 이를 순환 의존성(Circular Dependency)이라고 부른다.
순환 의존성?
A Class가 B Class를 참조하는데 B Class가 다시 A Class를 참조할 경우,
A Class가 B Class를 참조하고, B Class가 C Class를 참조하고 C Class가 A Class를 참조하는 경우 이를 순환 의존성(Circular Dependency)이라고 부른다.
불변성(Immutability)
Field Injection은 final을 선언할 수 없다. 그래서 객체가 변할 수 있다.
- 필드 주입 방식을 사용하여 작성된 클래스라면, 단위테스트시 의존 관계를 가지는 객체를 생성하여 주입할수 없다. 그 이유는 Field Injection은 숨은 의존성만 제공해 주기 때문이다.
(스프링 IOC가 생성해서 주입해주는 방식이어서 외부에 노출되는 것이 하나도 없기 때문에 의존 관계를 가지고 있는 메서드의 단위 테스트를 작성하면 NullOpintException이 발생하게 된다)
의존성이 숨는다.
- DI Container를 사용한다는 것은 Class가 자신의 의존성만 책임진다는게 아니라 제공된 의존성 또한 책임진다. Class가 어떤 의존성을 책임지지 않을 때, 메서드나 생성자를 통해(Setter나 Constructor) 확실히 커뮤니케이션이 되어야한다.
하지만 Field Injection은 숨은 의존성만 제공해준다.
그로인하여 Field Injection은 스프링 컨테이너 말고는 외부에서 주입할 수 있는 방법이 없다.
DI(Dependent Injection) Construct:의존성 주입중 생성자 주입 방식
전략패턴을 사용하게 되는것이다.
생성자를 사용하는 방법이 좋은 이유는 필수적으로 사용해야하는 의존성 없이는 Instance를 만들지 못하도록 강제할 수 있기 때문이다.
Spring 4.3버전부터는 Class를 완벽하게 DI Framework로부터 분리할 수 있다.
단일 생성자에 한해 @Autowired를 붙이지 않아도 된다. 한마디로 @Autowired가 붙어 있지만 써주지 않아도 되는것이지 알아서 적용되는 것이다. 없다고 생각하면 안된다.
의존관계 주입을 하지 않은 경우에는 Controller 객체를 생성할 수 없다.
- 즉, 의존관계에 대한 내용을 외부로 노출시킴으로써 컴파일 타임에 오류를 잡아낼 수 있다.
final을 사용할수있다.
- final의 장점은 객체가 불변하도록 할 수 있는 점으로, 누군가가 Controller 내부에서 Service 객체를 바꿔치기 할 수 없다는 점이다.
순환 의존성을 알 수 있다.
- 앞서 살펴 본 Field Injection에서는 컴파일 단계에서 순환 의존성을 검출할 방법이 없지만, Construtor Injection에서는 컴파일 단계에서 순환 의존성을 잡아 낼 수 있다.
의존성을 주입하기가 번거로워 위기감을 느낄 수 있다.
- Construtor Injection의 경우 생성자의 인자가 많아지면 코드가 길어지며 개발자로 하여금 위기감을 느끼게 해준다.
이를 바탕으로 SRP 원칙을 생각하게 되고, Refactoring을 하게 된다.
생성자 주입과 비교한 다른 방식들의 문제점으로 인하여 스프링 4.x이상에서는 개발자들이 Constructor Injection을 권장한다.
참고자료
DI