본문 바로가기

Spring

2. DI (Dependency Injection)의 개요

Spring의 핵심 중 한 개는 DI라고도 할 수 있다. 그렇다면 DI가 왜 필요한지, 그리고 어떻게 사용하는지에 대해서 간단하게 정리해보자.

 

주로 JavaEE 기반 Application을 개발할 때는 하나의 수행을 위해 여러개의 컴포넌트를 조합해서 구현한다.

MVC 기반 방식에선 공통으로 사용되는 Component, 데이터베이스에 접근하기 위한 Repository, 외부 시스템이나 서비스에 접속하기 위한 Component에 접근하기 위해 조합하는 경우가 많다.

결합도가 강한 프로그램

서로 조합해서 기능을 사용하기 위해선 각각의 컴포넌트들의 객체생성은 피할 수 없다.

객체를 생성할수록 의존성이 강해지게되며 그 결과 결합도가 높아지게 된다. 결합도가 높을수록 아래와 같은 문제점이 발생된다.

- 결합된 클래스가 변경될 경우 이와 연관된 클래스도 변경해야 하는 불편함이 발생
- 수정하려는 클래스를 이해하기 위해 연관된 클래스도 이해가 필요
- 다른 프로그램에서 클래스 재사용이 힘들어짐

즉, 이후에 유지보수성이 엄청나게 떨어진다는것이다.

 

이를위해 간단한 샘플을 보자.

Aridom은 출퇴근을 위해 세단을 샀다고하자.

public interface Car {
	String drive();
}

public class Sedan implements Car {

	@Override
	public String drive() {
		return "Drive a sedan.";
	}
	
}

public class DriveCar {

	private Car car;
	
	public DriveCar() {
		this.car = new Sedan();
	}
	
	public String drive() {
		return car.drive();
	}
	
}

Car 인터페이스는 단순히 주행하는 메소드인 drive가 있으며 Sedan 클래스는 Car 인터페이스를 구현하여 운전을 주행하는 메시지를 출력한다. DriveCar 클래스의 생성자는 Sedan 객체를 직접 생성하여 자동차를 운전할 수 있도록 되어있다.

 

이때까지만해도 세단차만 몰아도 충분했지만 문제는 로또 당첨으로 인하여 SUV 자동차도 구입하게 되었다.

public interface Car {
	String drive();
}

public class Sedan implements Car {

	@Override
	public String drive() {
		return "Drive a sedan.";
	}
	
}

public class Suv implements Car {

	@Override
	public String drive() {
		return "Drive a Suv.";
	}
}

public class DriveCar {

	private Car car;
	
	public DriveCar() {
		this.car = new Sedan(); // 세단도 타고 싶고
		this.car = new Suv(); // Suv도 타고 싶고...
	}
	
	public String drive() {
		return car.drive();
	}
	
}

이처럼 2개의 자동차를 서로 바꾸면서 타기위해선 DriveCar 클래스 생성자에서 직접구현한 Car Class 들을 수정해줘야하는 불편함이 생긴다.

결합도를 낮춘 프로그램

객체를 직접 생성자에 생성하는것이 아닌 다음과 같이 생성자의 인수로 받아서 할당하는 방법을 보자.

public class DriveCar {

	private Car car;
	
	public DriveCar(Car car) {
		this.car = car;
	}
	
	public String drive() {
		return car.drive();
	}
	
}

이렇게 하면 DriveCar 내부에 Car를 구현한 클래스 정보가 제거되어 외부에서 구현체를 생성하여 쉽게 변경할 수 있게된다. 이러한 방식이 의존성 주입(DI)이며 컴포넌트를 외부에서 생성한 후, 내부에서 사용 가능하게 만들어준다. 즉, 하나의 클래스를 수정하더라도 다른 클래스도 수정해야하는 문제를 방지할 수 있다.

추가적으로 의존성 주입을 자동으로 처리하는 기반을 DI 컨테이너 라고 한다.

Spring을 이용한 DI 방식

Spring의 DI를 이용할 경우 의존 객체들을 DI 컨테이너라는 곳에 저장하게 되며, 의존 관계를 서로 정의해주면 Spring이 알아서 주입시켜주게 된다. 그렇다면 이후에 Spring DI 컨테이너에서 의존객체를 가져올 땐 어떻게 할까?

 

다음과 같이 ApplicationContext라는 DI 컨테이너로부터 가져와 사용할 수 있다.

ApplicationContext에 대한 상세한 내용은 이후에 다루도록 하자.

ApplicationContext context = ...;
Car car = context.getBean(Sedan.class);