[Spring] 스프링 의존성 주입(DI) 이란?

pastaCoder·2022년 7월 20일
0

해당 주소의 글을 읽고 정리해봤다. https://devlog-wjdrbs96.tistory.com/165

✅DI(Dependency Injection)란?

Inversion of Control 이라고도 하는 의존 관계 주입(Dependency Injection)이라고도 하며, 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하는게 아니라, 주입 받아 사용하는 방법이다. (new 연산자를 이용해서 객체를 생성하는 것이라고 생각하면 된다)

장난감들은 베터리가 있어야 움직일 수 있으며 즉 베터리에 의존하고 있다. 장난감들에게 베터리를 넣어주는 것을 의존성 주입이라고 생각하면 좋다.

자바코드로 예시를 들어보자

베터리의 일체형인 경우에는 생성자에서만 의존성을 주입해주는 상황이라 베터리가 떨어지게 된다면 다른 베터리로 교체하지 못하고 새로운 것으로 바꿔야 하기 때문에 유연하지 못한 방식이다.

setter, 생성자를 이용해서 외부에서 주입해주는 상황은 외부에서 베터리를 교체해줄 수 있기 때문에 일체형보다 유연한 상황이다.
실제로 위 글의 링크를 들어가보면 똑같이 적혀있다. 그런데 여기서 왜 굳이 저렇게 만들어야 하는지가 궁금하다. 유연하다고는 하는데 유연하면 장점이 뭔지, 유연해지기 위해서 저런 DI라는 개념을 만들어서 사용해야만 하는 이유가 뭔지 그런부분을 더 찾아봤다.

출처: DI는 왜 써야할까

class Program {
	private IMacBook mac;

	public Program() {
		this.mac = new MacBook();
	}

	public StartMacBook() {
		this.mac.boot();
	}
}

위 코드에서 boot 메서드를 호출하기 위해서는 MacBook 클래스가 필요로 한다. 여기서 Program 클래스는 MacBook 클래스의 의존성을 가진다고 말할 수 있다. 하지만 위 코드는 의존성을 Program 클래스 내에서 생성한다.

위와 같이 코드를 작성하면, 코드의 재활용성이 떨어지고 MacBook 클래스를 수정하면 Program 클래스도 수정해야하는 문제가 발생한다. 지금은 하나의 클래스지만 수많은 클래스에서 MacBook를 사용하면 하나씩 수정해야 하는 이슈가 있다. 결국, Coupling(결합도)이 높아진다. 그리고 Unit Test를 하기 어려워진다.

위 코드에 DI를 적용하면 아래 코드가 된다.

class Program {
	private IMacBook mac;

	@Autowired
	public Program(IMacBook mac) {
		this.mac = mac;
	}

	public StartMacBook() {
		this.mac.boot();
	}
}

Program에 IMacBook 이라는 인터페이스를 주입했다. 인터페이스를 전달했으며, 객체가 변화되더라도 Program Class는 변경할 필요가 없어진다. IMacBook에 어떤 클래스를 전달할 지만 정하면 된다. 또한, 연결된 Class를 바꿔야 한다면 해당 Class 이름만 바꾸면 된다.
쉽게말해서 IMacBook 타입의 객체가 들어가기만 한다면 어차피 this.mac.boot();는 똑같이 실행되니 객체만 전달하는형태로 바뀐다. 그래서 실제로 IMacBook이 변해도, 다른 객체를 받아도 코드는 거의 변경되지않는다.

✅DI 사용 방법

@Autowired 어노테이션을 달아줄 경우 스프링이 연관된 객체를 스프링 컨테이너에 찾아서 넣어준다.

1. Constructor Injection - 생성자 주입

public class ClassName {
	private final IMacBook mac;

	@Autowired
	public ClassName(IMacBook mac) {
		this.mac = mac;
	}
}

2. Method(Setter) Injection - setter()을 통한 전달

public class ClassName {
	private IMacBook mac;
	
	@Autowired
	public void setMacBook(IMacBook mac) {
		this.mac = mac;
	}
}

3. Field Injection - 일반적인 변수 선언만으로 전달

public class ClassName {

	@Autowired
	private IMacBook mac;
	
}

✅생성자 주입방법을 권장하는 이유

생성자 주입 방법이 더 좋은 이유
순환 참조를 방지할 수 있습니다.

순환 참조 발생 시, 애플리케이션이 구동되지 않습니다.
테스트에 용이합니다.

단순 POJO를 이용한 테스트 코드를 만들 수 있습니다.
코드의 품질을 높일 수 있습니다.
불변성을 얻을 수 있습니다.

final을 사용할 수 있습니다.
실행 중에 객체가 변하는 것을 막을 수 있습니다.
오류를 방지할 수 있습니다.

0개의 댓글