DI(Dependency Injection)
의존 관계
DI 설명하기 전 의존관계를 먼저 설명하겠습니다.
의존관계 : "A가 B를 의존한다."
의존대상 B가 변하면 A에 영향을 미친다.
- 이일민, 토비의 스프링 3.1, 에이콘(2021)
의존대상인 B가 변경할 때 A의 영향이 미칩니다.
현실에서 예시를 찾을 경우 "공휴일은 규정에 의존합니다."
1. 관공서 공휴일에 관한 규정에 따라 부처님 오신 날, 기독탄신일을 대체 공휴일로 선정하였습니다.
2. 식목일은 법 개정으로 2006년 공휴일에서 제외되었습니다.
이와 같이 공휴일은 규정에 의존하기 때문에 규정 변경될 때 공휴일이 생길 수도 없어질 수도 있습니다.
다음과 같이 코드로 표현할 수 있습니다.
public class Holiday{
private Rule rule;
public Holiday(){
this.rule = new Rule();
}
}
규정이 변경될 때 다른 결과를 가져오기 때문에 큰 영향을 끼칩니다.
영향을 느슨하게 적용하기 위해 interface로 추상화해 보겠습니다.
public class Holiday{
private Rule rule;
public Holiday(){
this.rule = new RuleV1Impl();
}
}
# Rule interface
public interface Rule{
RuleInfo getHolidayRule();
}
# Rule Implements
public class RuleV1Impl implements Rule{
public RuleInfo getHolidayRule(){
...
}
}
지금까지는 Holiday에서 직접 new 키워드를 통해 instance를 생성하여 의존 주입하였습니다.
interface를 사용하여 결합도는 낮췄지만, 객체 지향 5원칙(SOLID)의 DIP 원칙을 위배하고 있습니다.
DIP(Dependency Inversion Principle)
- 추상화(인터페이스)에 의존해야지, 구체화(구현 클래스)에 의존하면 안 된다.
객체 지향 5원칙은 추후 포스팅하도록 하겠습니다.
이 문제를 DI(Dependency Injection, 의존 관계 주입)를 통해 해결할 수 있습니다.
의존 관계 주입 : 외부에 의해 관계가 주입됩니다.
현실에서도 규정은 각 관할 부처에서 법을 발의하여 규정을 만들게 됩니다.
코드에서는 해당 역할을 Spring framework에서 의존 관계 주입(DI)을 해줍니다.
DI 구현방법 3가지
1. setter 주입
setter는 외부에서 쉽게 접근하여 변경가능하므로 유지보수 시 큰 문제가 생길 수 있습니다.
따라서 해당 방식에 대해 이해는 필요하지만 사용하면 안 됩니다.
public Holiday{
private Rule rule;
public void setHoliday(Rule rule){
this.rule = rule;
}
}
2. Field 주입
Spring의 @Autowired를 통하여 Fild에 의존 관계를 주입할 수 있습니다.
외부에서 접근이 불가능하여 테스트 코드 작성 시 어려움이 있기 때문에 생성자 주입 사용을 권장합니다.
@Component
public class Holiday{
@Autowired
private Rule rule;
}
3. 생성자 주입
생성자를 통해 의존 관계를 주입하는 방법입니다.
Spring은 생성자 주입을 적극 지원하며, 싱글톤 방식으로 객체를 생성하기 때문에 객체가 변하지 않습니다.
@Component
public class Holiday{
private Rule rule;
public Holiday(Rule rule){
this.rule = rule;
}
}