Spring

Spring의 DI 컨테이너 (IOC 컨테이너)

이세형 2020. 11. 8. 14:30

이번글에서는 Spring DI 컨테이너를 좀더 자세히 알아보고 DI 컨테이너를 Spring에서 Java code로 설정해보는 방법에 대해서 알아본다.

 

그전에 그림과 함께 DI 컨테이너(DI)가 어떻게 OCP,DIP를 해결해주는지에 대해 복습해보자.

 

1
2
3
4
5
public class Car {
//     private Engine engine = new EngineA();
    private Engine engine = new EngineB();
}
 
cs

 

위와 같은 코드의 클래스 다이어 그램을 의존관계와 함께 나타내보면 아래와 같다.

 

Car 클래스는 interface인 Engine에도 의존하지만 구현체 클래스인 EngineA, EngineB에도 의존한다.

계속해서 반복하지만 구현체를 직접 선택해야하기 때문에 OCP와 DIP를 위반한다.

 

하지만 실행시점에 DI 컨테이너라는 것이 존재해서 의존성을 주입해준다고 하면 클래스 다이어 그램과 코드가 아래와 같이 바뀌게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Car {
 
    private Engine engine;
 
    public Car(Engine engine) {
        this.engine = engine;
    }
 
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
 
}
 
cs

 

DI Container가 모든 구현체(Instance)를 생성을 담당하며 의존 관계를 파악하고 있어 필요한 의존성을 주입해준다면 위와 같은 관계가 된다. 이렇게 되면 Car가 interface에만 의존하기 때문에 DIP 위배문제를 해결하고 당연히 따라서 코드를 변경하지 않으면서 실행시점에 구현체를 변경할 수 있기에 OCP 위배문제 마저 해결할 수 있다.

 

Spring에서는 이런 역할을 해주는 DI Container를 제공한다.

 

Spring 에게 클래스간 의존관계를 명세해주면 Spring이 해당 명세서를 읽고 DI Container가 해당 명세서에 맞게 잘 동작하도록 지원해준다.

 

즉 DI Container를 위한 설정값을 사전에 등록해놓으면 이를 바탕으로 완벽하게 Spring이 DI기능을 제공한다는 말이다.

 

이를 설정하는 방법은 크게 XML 파일을 이용한 방법, Java Code를 이용한 방법등 다양한 방법이 있는데 요즘 대부분 Java Code를 이용하는 방법을 많이쓰기때문에 이에 대해서 아주 간단하게 다뤄보도록 한다.

 

Annotation과 java 코드를 이용해 DI Container를 설정할수있다.

@Configuration을 통해 객체간의 의존관계에 대한 명세서(설정)클래스임을 명시하고

해당 인스턴스를 반환하는 메소드 위에 @Bean이라는 Annotaion 달아주면 해당 인스턴스를 DI container가 이를 Spring Bean 객체로 생성하고 싱글톤으로 관리해준다. 싱글톤에 대해서는 다음에 좀 더 자세히 다뤄보도록 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class AppConfig {
 
    @Bean
    public Car car() {
        return new Car(new EngineA());
    }
 
}
cs

아주 간단한 형태의 명세서이다. (Car는 EngineA를 의존한다)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
public class Main {
 
    public static void main(String[] args) {
 
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        Car car = ac.getBean("car", Car.class);
        System.out.println("car = " + car + " engine = " + car.getEngine());
    }
 
}
cs

ApplicationContext라고 하는것이 DI Container이며 해당 컨테이너에서 car 와 engine인스턴스를 생성하고 의존관계를 관리하게 된다.

이를 조회하여 출력해보면 아래의 결과와 같다.

 

Car의 instance가 명세서에 표기한 engineA를 사용하고 있음을 보여준다.

다음 글에서는 싱글톤이 무엇인지, DI Container가 왜 싱글톤으로 인스턴스를 관리하는지에 대해서 알아보도록 한다.

 

#Reference

스프링 핵심 원리 - 기본편 (김영한)

www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8