백엔드

의존성 주입!

skgur07 2024. 8. 2. 23:36

 

의존성 주입을 배우기 이전


Spring은 3가지의 핵심 프로그래밍 모델을 지원한다. AOP, DI, IoC 을 지원합니다. 이중에서 오늘은 DI 에 대해 알아보겠습니다.

 

사용하는 이유


Spring 은 객체의 의존 관계를 외존 관계 주입을 통해 관리합니다.

DI 를 통해 객체 간의 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있습니다.

이제 본격적으로 의존성 주입 DI 이에 대해 알아봅시다.


의존성 주입 ( Dependency Injection, DI ) :


의존성 :

의존성이란 한 객체가 다른 객체를 사용할 때 의존성이 있다고 표현합니다.

자바에서 의존성은 여러 형태가 있습니다. 가장 익숙한 방법은

new 를 사용해서 인스턴스를 생성하는 방법이있습니다.

예를 들어

Car 이라는 객체가 Engine 객체를 사용하고 있는 경우에 Car 이라는 객체가 Engine이라는 객체에 의존성이 있다고 표현합니다.

class Engine {
    public void start() {
        System.out.println("부릉! 부릉!");
    }
}

class Car {
    private Engine engine;

    public Car() {
        engine = new Engine(); 
        // Car가 직접 Engine을 생성
    }

    public void drive() {
        engine.start();
        System.out.println("달려!");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive();
    }
}

이런 경우에 Car 이라는 객체가 Engine 이라는 객체에 의존하고 있다고 표현합니다.

하지만 위와 같은 경우는 문제점을 가지고 있습니다.

Car 클래스는 Eninge 클래스에 강하게 결합되어 있습니다.

Car 이 직접 Engine 객체를 생성하기 때문에 engine을 교체하거나 테스트하기가 어렵습니다.

의존성 주입 ( DI ) :

객체간 의존성을 개발자가 객체 내부에서 직접 호출하는 대신, 외부에서 객체를 생성해서 넣어주는 방식입니다. 위에서 말 했다 시피 의존성 주입을 사용하면 객체 간의 결합도를 낮추고, 코드의 유연성과 재사용성을 높이며, 단위 테스트를 더 쉽게 작성할 수 있습니다.

직접 호출은 많이 사용하는 new 연산자고 있고,

외부는 스프링 컨테이너라고 볼 수 있습니다.

  • 스프링 컨테이너란 :
    • 스프링 프레임워크의 핵심 컴포넌트이다.
    • 스프링 컨테이너는 자바 객체의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공한다.

 

DI 의 3가지 방법


일단 의존성 주입에는 3가지 방법이 있다.

  • 생성자 주입
  • 필드 주입
  • Setter 주입

이 중에서 가장 권장되는 의존 관계 주입 방식은 생성자 주입 방식이다.

 

생성자 주입


생성자 주입은 객체의 의존성을 클래스의 생성자를 통해 주입하는 방식입니다. 스프링 공식 문서에서도 생성자 주입을 권장하며, 스프링 4.3 이후부터는 생성자가 하나만 있는 경우 @Autowired 어노테이션을 생략할 수 있습니다.

예시 :

public class TestConstructor {

	private final TestStart testStart;
	
	@Autowired -> 생략 가능
	public TestConstructor(TestStart testStart) {
		this.testStart = testStart;
	}
}

 

필드 주입


필드 주입은 클래스의 필드에 직접 의존성을 주입하는 방식입니다.

권장하지는 않습니다.

장점은 코드가 간결해지지만 final 키워드를 사용할 수 없어 불변성이 보장되지 않아 객체가 변할 수 있습니다.

예시 :

public class TestField {
	
	@Autowired
	private StartField startField;
}

 

Setter 주입


Setter 주입은 Setter 메서드를 통해 의존성을 주입하는 방식입니다.

낮은 버전에서 Setter 주입을 사용했지만 지금은 생성자 주입 방식 사용을 권장한다.

예시 :

public class TestSetter {
	    private StartSetter startSetter;        
	    
	    @Autowired    
	    public void testSetterService( StartSetter startSetter) {
	        	this.startSetter = startSetter;    
	     }
}

 

결론


생성자 주입은 불변성을 유지하고 의존성을 명확히 드러내는 장점 때문에 스프링에서 권장하는 방식이다. Setter 주입은 유연성을 제공하지만, 객체의 상태를 변경 가능하게 만들어 불변성을 유지하기 어렵기 때문에 생성자 주입 방식을 사용한다.