728x90
반응형
SMALL
의존 관계란 무엇인가?
Java는 객체지향 언어입니다. 따라서 객체들 간의 관계를 적절히 맺어주는 것이 매우 중요합니다.
"의존 관계"라는 것은 거창한 개념이 아닙니다.
A 인스턴스가 B 인스턴스의 메서드를 호출하고 있다면, A는 B에 의존하는 관계입니다.
A가 B의 기능을 가져다 사용하고 있으니까요.
class A {
public void methodOfA() {
B b = new B(); // A가 B를 직접 생성
b.example(); // B의 메서드를 사용 → A가 B에 의존
}
}
class B {
public void example() {
System.out.println("B의 기능 실행");
}
}
기존 방식의 문제점
위 코드에서 A와 B의 의존 관계는 개발자가 직접 만들었습니다.
`new` 키워드로 직접 인스턴스를 생성했기 때문입니다.
하지만 이 방식에는 심각한 문제가 있습니다.
상황: A가 B 대신 새로운 클래스 C를 사용하고 싶다면?
class A {
public void methodOfA() {
// B b = new B(); // 기존 코드 삭제
// b.example();
C c = new C(); // 새로운 코드 추가
c.example();
}
}
class C {
public void example() {
System.out.println("C의 기능 실행");
}
}
문제: 만약 B를 사용하던 클래스가 A 하나가 아니라 수십, 수백 개라면?
→ 모든 클래스의 코드를 일일이 수정해야 합니다.
DI 방식으로 해결하기
스프링의 DI를 사용하면 이 문제를 해결할 수 있습니다.
핵심 아이디어
- 직접 객체를 만들지 않는다.
- 외부에서 만들어서 넣어준다(주입)
1단계: 추상화 (인터페이스 도입)
- A가 직접 B를 알지 않도록,
- A가 필요로 하는 기능을 인터페이스로 정의
2단계: 구현체들이 인터페이스를 구현
// A가 사용하는 메서드를 인터페이스로 추상화
interface I {
void example();
}
class B implements I {
public void example() {
System.out.println("B의 기능 실행");
}
}
class C implements I {
public void example() {
System.out.println("C의 기능 실행");
}
}
3단계: 외부 주입 방식으로 변경
- A는 인터페이스만 의존
- 어떤 구현체를 쓸지는 ‘외부’가 결정
class A {
private I i; // 인터페이스 타입 필드
// 생성자를 통해 외부에서 구현체를 받음
public A(I i) {
this.i = i;
}
public void methodOfA() {
i.example(); // 어떤 구현체든 상관없이 호출
}
}
핵심 변화
Before (기존 방식):
- A가 직접 B를 생성: `B b = new B()`
- A가 B에 강하게 결합됨
After (DI 방식):
- A는 자신이 사용할 객체를 알지 못함
- A는 단지 `i.example()` 메서드가 있다는 것만 알고 있음
- 외부에서 A에게 필요한 객체를 주입해줌
누가 의존성을 주입해주는가?
그렇다면 누군가가 A에게 필요한 객체(B든 C든)를 결정하고 생성해서 전달해주어야 합니다.
그 누군가가 바로 스프링입니다!
// 개발자는 설정만 해둡니다
@Configuration
public class AppConfig {
@Bean
public I getImplementation() {
return new C(); // C를 사용하겠다고 설정
}
@Bean
public A getA(I i) {
return new A(i); // 스프링이 자동으로 C를 주입해줌
}
}
동작 과정:
- 개발자가 설정 파일에 "A는 C를 사용하겠다"고 설정
- 애플리케이션 실행 시 스프링이 설정을 해석
- 스프링이 C 객체를 생성
- 스프링이 A 생성자에 C를 전달하여 A 생성
- A는 C가 주입된 상태로 사용 가능
DI의 장점
- 유연성: B에서 C로 바꾸려면 설정 파일만 수정하면 됨
- 재사용성: A 클래스 코드 변경 없이 다양한 구현체 사용 가능
- 테스트 용이성: Mock 객체를 쉽게 주입할 수 있음
- 결합도 감소: A는 구체 클래스(B, C)를 몰라도 됨
728x90
반응형
LIST