의존성 주입
객체가 필요로 하는 어떤 것을 외부에서 전달해주는 행위를 말하며,
포괄적인 의미로서 두 객체 간의 관계를 외부에서 결정해주는 디자인 패턴을 의미합니다.
예시(의존성 주입이 아닌 경우)
class Eat {
private Meat meat;
public Eat(){
this.meat = new Meat();
}
public void eatMeat(){
this.meat = new Meat();
}
- 현재 Eat 클래스에서 Meat 객체를 사용하고 있는 예시 : "Eat 클래스가 Meat 클래스에 의존성이 있다"고 표현합니다.
- Eat 생성자를 통해 Meat를 직접 생성하는 경우 : 의존성 주입이 이뤄지지 않았습니다.
- 이유 : 객체에서 필요한 Meat 클래스를 내부에서 생성하고 있기 때문입니다.
- 메소드(Setter, eatMeat) 를 통해 Meat를 직접 생성하는 경우 : 의존성 주입이 이뤄지지 않았습니다.
- 이유 : 이 또한 객체에서 필요한 Meat 클래스를 내부에서 생성하고 있기 때문입니다.
예시의 단점 (의존성 주입이 필요한 이유)
1. 높은 결합도 : 유지보수 측면에서 유연하지 못해 불리합니다.
- 위 예시에서 Eat 클래스를 통해 Meat 가 아닌 다른 것을 먹으려 할 시 생성자와 메소드 자체에 변경이 필요합니다.
class Eat {
private Meat meat;
// private Vegetable veg;
class Eat(){
this.meat = new Meat();
// this.veg = new Vegetable();
}
void eatMeat(){
this.meat = new Meat();
}
// void eatVegtable(){
// this.veg = new Vegetable();
// }
2. 객체지향과는 먼 거리의 설계 : 객체 간의 관계가 아닌 클래스 간의 관계가 맺어집니다.
3. 필요하지 않아도 종속되는 관계 : Eat이라는 클래스에 Meat이 종속되므로 Eat 생성 시 Meat을 먹을 수 밖에 없습니다.
따라서, 이러한 문제점은 외부에서 객체에게 필요한 것을 전달하는 "의존성 주입"이라는 개념을 통해 해결합니다.
의존성 주입의 방법
java, Spring의 의존성 주입은 객체 내에서 필요한 다른 객체를 생성자 또는 Setter를 통해 주입하는 것을 의미합니다.
종류로는 크게 생성자 주입, 인터페이스 주입, 필드 주입, 세터 주입이 있습니다.
생성자 주입
class Eat {
private Meat meat;
// 생성자 주입
public Eat(Meat meat){
this.meat = meat
}
class Meat{}
class Beef extends Meat{}
class Pork extends Meat{}
현재 Eat은 생성자의 인자로서 Meat을 넘겨받습니다, 이는 생성자로 의한 의존성 주입이 된 형태입니다.
- 이를 통해 Eat은 필요로 할 때 Meat을 외부에서 넘겨받아 생성할 수 있습니다.
- Meat을 상속받는 파생 클래스도 다형성에 의해 Eat에 전달될 수 있습니다.
- 생성자 주입은 불변성을 유지하고자 할때 사용합니다. (생성과 동시에 성질이 불변함으로)
인터페이스 주입
// Meat 인터페이스
interface Meat {
String cook();
}
// Eat 클래스 with 인터페이스 주입
class Eat {
private final Meat meat;
public Eat(Meat meat) {
this.meat = meat;
}
}
// 구체적인 Meat 구현 클래스들
class Beef implements Meat {
@Override
public String cook() {
return "Grilled beef";
}
}
class Pork implements Meat {
@Override
public String cook() {
return "Roasted pork";
}
}
현재 Eat은 Meat 인터페이스를 통해 Meat을 넘겨받습니다. 이는 인터페이스로 인한 의존성 주입이 된 형태입니다.
- Eat 클래스는 Meat의 구현체를 받아들일 수 있게 되어 유연성이 높아집니다.
세터 주입
class Eat {
private Meat meat;
// 세터 주입
public void setMeat(Meat meat) {
this.meat = meat;
}
}
class Meat {}
class Beef extends Meat {}
class Pork extends Meat {}
세터 주입은 동적으로 의존성을 변경할 수 있을 때 사용합니다.
따라서 선택적으로 의존성을 변경할 필요가 있을 때 사용합니다.
- 동적인 의존성 변경 : setMeat 메소드를 통해 Eat의 필드 Meat을 바꿀 수 있습니다.
필드 주입
lass Eat {
private Meat meat;
// 필드 주입
public Eat() {}
public void setMeat(Meat meat) {
this.meat = meat;
}
}
class Meat {}
class Beef extends Meat {}
class Pork extends Meat {}
필드 주입은 NoArgsConstructer 생성자로 인한 생성 후 Setter를 통한 필드 주입 방법을 사용합니다.
즉, 클래스 초기화 후 필드 값을 단독으로 주입하는 경우입니다.
필드 주입은 아래와 같은 이유로 사용이 지양됩니다.
- 불변성 미준수 : 필드 주입은 주입 의존성을 변경할 수 있음
- 의존성 숨김 어려움 : 필드 주입 사용 시 어떤 의존성을 가지고 있는지 명시적으로 드러나지 않아 코드 복잡도 증가
- 순환 의존성 문제 : 필드 주입 사용 시 A가 B 필드를 가지고 있고, B가 A 필드를 가지고 있으면 예외 발생 가능성 증가
다음 포스팅에서 이어집니다.
2023.11.16 - [DEV/Spring] - [Spring] @Autowired 활용 의존성 주입, Spring Bean (2 / 2)
[Spring] @Autowired 활용 의존성 주입, Spring Bean (2 / 2)
이전 포스팅에서 이어집니다. 의존성 주입(Dependency Injection) (1 / 2)의존성 주입 객체가 필요로 하는 어떤 것을 외부에서 전달해주는 행위를 말하며, 포괄적인 의미로서 두 객체 간의 관계를 외부
doinitright.tistory.com
'DEV > Spring' 카테고리의 다른 글
[Spring] @Configuration을 활용한 @Bean 등록 방법 (0) | 2023.11.23 |
---|---|
[Spring] @RequestParam의 이해 (0) | 2023.11.21 |
[Spring] @Autowired 활용 의존성 주입, Spring Bean (2 / 2) (0) | 2023.11.16 |
[Spring Boot] java 기반 Spring Boot 프로젝트 생성 방법 (0) | 2023.10.12 |
[Spring Boot] ORM, JPA의 개념과 JPA 사용 설정 (0) | 2023.09.13 |