의존 객체 주입

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

구현 객체가 프로그램의 제어 흐름을 스스로 컨트롤하는 것이 아닌 외부에서 관리되는 것제어의 역전 이라고 부른다.

DI: 의존 관계, 의존성 주입

스프링은 빈으로 등록된 객체들을 객체 내에서 생성하는 것이 아닌 외부에서 입력받아 사용 하는 형태로, 객체간의 의존성을 줄인다. 외부에서 받아오는 형태기 때문에 객체들 사이에서 독립성이 증가하여 의존관계를 파악하기 쉬워지며 코드의 유지보수가 편리해진다.

어플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된다.

Field Injection(필드 주입)

@Controller
public class SampleController {

    @Autowired
    private SampleService sampleService;
}

변수 선언부에 @Autowired 를 붙여서 의존성을 주입한다. 생성자도 setter 도 없이 의존성을 주입할 수 있어 간단하지만 몇가지 단점이 존재한다.

먼저, 외부에서 변경이 불가능하므로 테스트하기 어렵다. 또 @Autowired 라는 DI 프레임워크가 없다면 어떠한 것도 할 수 없다. 예를 들어 해당 코드에서 스프링 프레임워크를 제거하면 코드가 동작하지 않는다. 반면, 생성자나 setter 주입은 @Autowired 가 없어도 동작한다. 또, 의존성 주입받은 필드에 final 키워드로 선언할 수 없어 불변성이 깨진다.

따라서 필드 주입은 프로덕션 코드가 아닌 테스트 코드에서 사용하는 것을 권장한다.

Setter Injection(수정자 주입)

@Controller
public class SampleController {

    private SampleService sampleService;
 
    @Autowired
    public void setSampleService(SampleService sampleService) {
        this.sampleService = sampleService;
    }
}

setter 메소드를 이용하여 의존성을 주입한다. 주로 선택이나 변경 가능성이 있는 의존 관계에서 사용한다. 상황에 따라 다른 객체를 주입할 수 있다는 장점이 있다. 다만, setter 메소드를 이용할 경우 아직 주입되지 않은 값을 호출하면 NullPointerException 이 발생할 수 있다.

Constructor Injection(생성자 주입)

@Controller
public class SampleController {

    private final SampleService sampleService;
 
		// @Autowired 키워드 생략 가능
    @Autowired
    public SampleController(SampleService sampleService) {
        this.sampleService = sampleService;
    }
}

생성자에서 의존성을 주입받는다. 최신 버전의 스프링을 사용할 경우 @Autowired 키워드는 생략이 가능하다. SampleService 가 생성되는 시점에 값을 주입받으므로 값이 없는 경우는 없고(setter 문제점 해결), final 키워드 또한 붙일 수 있다.(필드 문제점 해결)

https://velog.io/@gillog/Spring-DIDependency-Injection-세-가지-방법