본문 바로가기
기술/Spring-Boot

의존성 주입(DI)이 뭘까?

by Zabee52 2021. 11. 28.

DI(Dependency Injection)

스프링 용어를 찾아보다보면 가장 먼저 접하고 매우 빈번하게 보게 되는 단어가 바로 DI다. 의존성 주입. 이게 대체 뭘 하는 녀석일까?

 

이것에 대해 설명하려면 IoC Container라는 스프링의 핵심 구성요소에 대해 알아야 한다. 설명하자면 시간이 오래 걸릴테니, 시간이 부족한 분들을 위해 정말 간략하게 IoC Container가 뭔지 설명을 하자면,

 

  1. 제어 반전 컨테이너(Inversion of Control Container)의 약자로,
  2. 오브젝트를 관리해주는 스프링의 객체인 BeanFactory 또는 ApplicationContext를 이용해서
  3. 사용자가 만든 객체를 자동으로 호출해 Bean으로 등록해 사용하게 해주는 것을 말한다.

여기서 핵심은, 일반적으로 사용자가 객체를 호출해 사용하는 것이 아닌, 외부에서 호출해 사용할 수 있도록 하는 점으로, 그렇기 때문에 제어가 반전되어있다는 표현을 사용하는 것이라고 볼 수 있다.

 

그러면 IoC Container와 DI는 무슨 관계가 있는가 하면, 감이 빠른 사람들은 알겠지만, 사용자가 객체를 자동으로 호출해 Bean으로 등록하는 행위를 하는것을 바로 의존성 주입(DI, Dependency Injection)이라고 한다.

 

여기서, 그러면 스프링은 의존성 주입이 뭐가 좋아서 이런 기능까지 제공해주는것일까? 라는 의문이 들 수 있다. 이것에 대한 해답이 바로 DI의 핵심이라고 볼 수 있다.

 

객체지향 프로그래밍을 설계할 때 결국 중요한 점은 재사용성과 유지보수성을 높이는 것이다. 이 중 유지보수 측면에서, 만약에 사용자가 내부에서 직접 클래스를 선언해 사용하면 어떻게 될까?

class A{
    private TestClass b;
 
    A(){
        b = new TestClass();
    }
}

이렇게, 직접 클래스를 선언해 사용하는 구조라고 한다면, 지금은 A클래스 하나지만 100개의 클래스가 TestClass를 호출해서 생성해 사용하는 방식이라고 가정한다면, 이 때 만약 TestClass의 구조에 변경이 생긴다면 어떤 일이 벌어질까?

TestClass와 관련된 클래스를 전부 하나하나 수정해야하는 대참사가 벌어지게 될 것이다. 이렇게 객체의 변화에 기민하게 대처되지 못 하고 클래스간의 관계가 끈끈하게 의존되어 있는 상태를 결합도가 강하다(Tight Coupling) 라고 표현한다.

 

이걸 해결하는 방법은 무엇일까?

매뉴얼한 해결방안을 먼저 제시하자면, 클래스를 공동으로 사용할 수 있도록 하는 클래스를 별도로 만들어 관리하면 될 것이다. 근데 이거, 만드는거 꽤나 귀찮고 관리대상이 하나 늘어나버려서 사람을 힘들게 만든다. 그렇기 때문에 이걸 자동화 해주는 스프링의 DI를 활용하는 것이다.

@Component // 스프링에게 이 클래스를 인식시켜주는 어노테이션으로, 이 정도의 사전작업은 필요하다.
public class TestClass{
}
@RequiredArgsContructor // 스프링 : 생성자만 만들어놓으면 내가 다 해줄게! ٩( ᐛ )و
class A{
    private final TestClass b;
}

이렇게, 의존성이 필요한 클래스를 선언해놓고 그에 맞는 생성자만 만들어주면, 알아서 공용 저장소인 Bean에 이 클래스를 등록시켜 TestClass의 변화가 발생하더라도(물론 TestClass 내의 메소드가 사라진다거나 하면 문제가 생기겠지만) 추가적인 작업을 하지 않을 수 있게 되는 것이다. 정말로 편리하다.

 

 

그래서 결국에 DI는 무엇인가? 에 대해 요약을 해주자면

  1. 호출이 요구되는 클래스를
  2. 자동으로 정의해주는
  3. 착한 친구 ٩( ᐛ )و

라고 할 수 있겠다.

댓글