저작자: PHẠM HUY HOÀNG 이미지 출처 : https://toidicodedao.com/2015/11/03/dependency-injection-va-inversion-of-control-phan-1-dinh-nghia/

 

 

DI (Dependency Injection): 의존성 주입

- 외부의 컨테이너(Spring Conainer)에서 객체를 생성한 후 의존성을 주입시키는 설계 패턴

- 스프링에서 객체는 Bean 으로 표현된다. 

 

DI 사용의 장점

- 모듈 간의 결합도가 낮아져, 유연성이 높아짐 따라서 안정적인 테스트 가능 ( Mock 을 통해)

- *순환참조(Circular Reference) 제거

 

*순환참조(Circular Reference) : 참조하는 대상이 서로 몰려있어서 참조할 수 없게 되는 현상.

- 재사용이 높고, 코드 변경 및 확장의 영향이 적음 (추상화)

 

 

 

DI 사용 - 객체에 의존성을 주입시키는 방법

대표적으로 3가지 방법이 있다. 

[세터 기반 의존성 주입, 생성자 기반 의존성 주입, 필드 기반 의존성 주입]

 

 

 

 

 

1) 세터 기반 의존성 주입

- setter()메소드에 @Autowired를 지정하여 객체에 대한 의존성을 주입한다.

*@Autowired 란? 

- 자동연결 (Autowiring)을 뜻하며 스프링 DI에서 사용되는 어노테이션으로, 컨테이너에 빈을 자동으로 주입해준다(즉, @Autowired 가 붙은 필드에 자동적으로 의존성을 주입해줌).

- 변수, 생성자, Setter(), 일반 메소드에 적용가능하다

 

예시: StudentController.java 에 Student 객체를  setter()를 사용하여 의존성을 주입해보자

public class StudentController {
    private Student student; //의존성 주입 대상 필드

    //Setter 를 사용한 의존성 주입
    @Autowired
    public void setStudent(Student student){
        this.student = student;
    }
}

이 주입 방법은 순환 참조 및 결합도 (Coupling) 문제로 권장되지는 않는다.

 

 

 

 

 

2) 생성자 기반 의존성 주입

- 생성자에 @Autowired 애너테이션을 지정하여 객체에 의존성을 주입한다

- 세터기반의존성 주입에 비해 권장되는 방식이다.

예시: StudentController.java 에 Student 객체를 생성자를 사용하여 의존성을 주입해보자

public class StudentController {
    private Student student; //의존성 주입 대상 필드

    //생성자를 사용하여 의존성 주입
    @Autowired
    public StudentController(Student student){
        this.student = student;
    }
}

 

Lombok을 사용한다면 @RequiredArgsConstructor를 사용한다면 위와 같은 코드를 조금 더 간결하게 구현할 수 있다.

다만 의존성 주입 대상 필드는 꼭 final로 선언을 해주어야만 해당 필드를 가진 생성자가 만들어진다.

public class StudentController {
    private final Student student; //의존성 주입 대상 필드
}

 

 

 

 

 

3) 필드 기반 의존성 주입

단순히 필드에 @Autowired 를 붙여서 의존성을 주입하는 것

예시: StudentController.java 안에서 Student 객체(필드) 의존성을 주입해보자

public class StudentController {
    @Autowired
    private Student student; //의존성 주입 대상 필드
}

 


 

IoC(Inversion Of Control) : 제어의 역전

- 제어의 역전, 즉 제어권한이 뒤바뀌었다는 뜻 (권한이 개발자에서 프레임워크로)

- 예전 자바기반 어플리케이션은 개발자가 직접 자바 객체를 생성하고, 의존관계를 연결함 (제어권을 개발자가 가지고 있었음 => DI)

하지만, Servlet 과 EJB가 생겨나면서 객체의 생성/관리등의 제어권한이 외부의 컨테이너로 넘어가 뒤바뀌게 됨 (제어권을 컨테이너가 가지게됨) 이를 우리는 "제어의 역전", IoC라고 표현한다.

 

예시) 개발자가 직접 객체를 생성하는 코드

import BBB.BBB;

public class AAA {
    
    private BBB bbb;
    
    public AAA(){
        bbb = new BBB(); // AAA 객체안에서 BBB 라는 객체가 New 생성자로 직접생성됨
    }
}

기존에 객체를 생성했던 방법을 간단히 살펴보면, 위의 코드와 같이 객체 AAA안에서 BBB의 객체를 쓰려면 new BBB()로 직접 생성해야 했다(즉 개발자들이 직접 객체를 생성해서 사용해옴).

 

이 코드를 다시 해석하면 AAA 라는 객체는 BBB라는 객체를 사용(의존)하고 있는 것을 확인할 수 있는데, 이것을 IoC 의 형태로 바꿔서 쓰면 (의존성 주입) 다음과 같다.

 

예시) 컨테이너에 의한 객체를 사용하는 코드

import BBB.BBB;
import org.springframework.beans.factory.annotation.Autowired;

public class AAA {

    @Autowired
    private BBB bbb;

}

이 객체는 스프링 컨테이너에 의해 생성 및 관리되기 때문에 코드에서 직접 객체를 생성하지 않고 의존관계만 주입해주는 것을 확인할 수 있다. 이것을 우리는 제어가 역전되었다 (IoC) 라고 한다. 이를 간단하게 말하면,

'의존성을 주입해준다' = 외부(스프링 컨테이너)에서 객체의 레퍼런스(객체의 주소)를 전달하여 객체를 참조할 수 있게 한다.

 

 

따라서 스프링에서 객체가 만들어지고 실행되는 과정은 다음과 같다

객체 생성 -> 객체에 의존성 주입 (컨테이너에 의해 관리되어지는 객체) -> 의존성 주입된 객체의 메소드 호출 

 

 

 

IoC와 DI의 차이점

DI는 IoC 모델을 구현하는 방식중에 하나고,

 IoC(객체의 제어권한을 외부에서 관리)는 DI(외부에서 생성된 객체를 주입하는 것)를 통해 실현되는 것이라고 이해하면 될 것 같다. 큰 차이점은 없는 것으로 보인다.

 

References

https://velog.io/@gillog/Spring-DIDependency-Injection

https://junu0516.tistory.com/87

https://life-with-coding.tistory.com/433

'Web > Spring' 카테고리의 다른 글

Spring Boot JSP & Thymeleaf  (0) 2022.06.08
Spring - AOP  (0) 2022.01.07
Spring Boot 시작하기 1장 (Get API-@GetMapping)  (0) 2022.01.07

+ Recent posts