J.one_DevNote
[Spring]DI(의존성 주입) 본문
의존성 주입(Dependency Injection, DI)
이 글에서는 의존성 주입의 종류에 대해서 말하고자 한다.
https://j-one24.tistory.com/30
[Spring] IoC와 DI
제어의 역전(Inversion of Control, IoC) 스프링에서 제어의 역전(ex : interface를 이용한 impl을 만드는 것)을 하는 이유는 객체의 의존성을 역전시켜, 객체 간의 결합도를 줄이고, 코드의 수정/관리를 편하
j-one24.tistory.com
생성자 주입을 통한 의존성 주입(Constructor Injection)
생성자 주입을 통한 의존성 주입 방식은 의존성 주입 방식중에서 권장되는 방식으로 생성자 호출 시점에 1회 호출되는 것이 보장된다. 또한 필수적으로 사용하는 매개변수 없이는 인스턴스를 만들 수 없기에 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다.
@Service
public class Hello{
private SayHelloTest sayhellotest;
@Autowired
public Hello(SayHelloTest sayhellotest){
this.sayhellotest = sayhellotest;
}
...
}
Field변수를 이용한 의존성 주입(Method Injection)
필드 주입 방식은 필드 앞에 @Autowired 어노테이션을 명시한다. 필드 주입 방법으로 사용하면 주입한 것을 중간에 바꿀 수 있는 방법이 없다. 주입되는 변수를 private로 선언하기 때문에 이후 외부 접근도 불가능하다. 따라서 그다지 권장하지 않는 방법이다.
@Service
public class Hello{
@Autowired
private SayHelloTest sayhellotest;
...
}
setter를 이용한 의존성 주입(Setter Injection)
setter함수에 @Autowired 어노테이션을 명시한다. "sayhellotest"는 prviate으로 선언하고, 이후 setter함수가 호출되어 "sayhellotest"가 주입된다. setter 주입 사용 시 setter 함수가 public으로 노출되어 있어서, "sayhellotest"가 변경될 수 있는 환경이 된다. 외부에서도 얼마든지 Hello.setSayHelloTest()를 호출할 수 있다. 즉 주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.
@Service
public class Hello{
private SayHelloTest sayhellotest;
@Autowired
public void setSayHelloTest(SayHelloTest sayhellotest){
this.sayhellotest = sayhellotest;
}
...
}
생성자 주입을 통한 의존성 주입(Constructor Injection)을 권장하는 이유는?
1. 단일 책임의 원칙
가장 많이들 사용하는 Field Injection은 의존성 주입이 너무 쉬우므로 무분별한 의존성을 주입할 수도 있다. 그러면 하나의 클래스에서 지나치게 많은 기능을 하게 될 수 있는 여지가 있고, ‘객체는 그에 맞는 동작만 한다’라는 단일 책임의 원칙이 깨지기 쉽다.
Constructor Injection을 사용하면 의존성을 주입해야 하는 대상이 많아질수록 생성자의 인자가 늘어난다. 이는 의존관계의 복잡성을 쉽게 파악할 수 있도록 도와주므로 리팩토링의 실마리를 제공한다.
2. DI Container와의 낮은 결합도
Field Injection을 사용하면 의존 클래스를 곧바로 인스턴스화 시킬 수 없다. 만약 DI Container 밖의 환경에서 의존성을 주입받는 클래스의 객체를 참조할 때, Dependency를 정의해두는 Reflection을 사용하는 방법 외에는 참조할 방법이 없다. 생성자 또는 Setter가 존재하지 않는다면 의존 객체 필드를 설정할 수 있는 방법이 없기 때문이다.
Constructor Injection은 생성자로 의존성을 주입받기 때문에 DI Container에 의존하지 않고 사용할 수 있고, 그 덕분에 테스트에서도 더 용이함을 보인다.
3. 필드의 불변성 보장
Field Injection은 객체를 생성하고 의존성을 Reflection으로 주입받기 때문에 필드 변수를 Immutable로 선언할 수 없다.
그러나 Constructor Injection은 필드를 final로 선언할 수 있기 때문에 필드의 변경에 대해 안전하다. 이는 객체의 변경에 따른 비용을 절약할 수 있도록 도와준다.
4. 순환 의존 방지
Constructor Injection에서는 순환 의존성을 가질 경우 BeanCurrentlyInCreationException이 발생해서 문제 상황을 알 수 있게 해준다.
이와 같은 이유로 Spring 4.x 이후부터는 Constructor Injection을 사용하기를 권장하고 있다.
**Reflection :
1) 구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들을 접근할 수 있도록 해주는 자바 API 이며,
2) 컴파일 시간이 아닌 실행 시간에 동적으로 특정 클래스의 정보를 추출해낼 수 있는 프로그램 기법 이다.
리플렉션: 스프링의 DI는 어떻게 동작하는걸까?
이제까지 자바와 스프링으로 개발을 해왔지만, 한번도 의존성 주입이 어떻게 이루어지는지 궁금해하지 않고 당연한 것처럼 써왔다.이번 기회를 통해, 스프링 내부 동작 방식에 대해 공부해보려
velog.io
'Spring' 카테고리의 다른 글
Echart를 이용하여 지도 표출하기 (0) | 2024.05.30 |
---|---|
Spring에서 Python 사용하기 (0) | 2024.05.29 |
[Spring] Bean과 Annotation (0) | 2023.01.11 |
[Spring] IoC와 DI (0) | 2023.01.11 |
[Spring] SOLID 원칙 (0) | 2023.01.11 |