IT

[Spring] 스프링 DI

data-cloud 2025. 1. 18. 11:09
반응형

 

 

 

🌱 스프링 삼각형

 

이전 포스팅 중 '스프링 개요'에서 스프링을 구성하는 핵심 요소에 대하여 알아봤었다.
오늘은 그중에서 DI에 대하여 조금 더 상세하게 포스팅하려고 한다.

 

 

 

🌱 DI (Dependency Injection)

의존성 주입(DI)이란, 객체를 직접 생성하는 것이 아니라 외부에서 객체를 생성한 후 주입 시켜주는 방식을 뜻한다.

일반적인 스프링 프로젝트 코드를 살펴보면, Controller에서 Service나 Repository 객체를 사용할 때, new 키워드를 통해 객체를 직접 생성하는 것이 아니라 스프링 컨테이너에 생성된 객체를 받아오는 방식으로 사용하는 것을 볼 수 있었을 것이다.

이를 통해 결합도를 낮추고 유연성을 높일 수 있기 때문이다.

결합도를 낮추고 유연성을 높인다는게 정확하게 와닿지 않을 수 있으니 아래의 그림을 통해 단계적으로 알아가 보자.

 

A객체에서 B와 C객체를 사용한다고 할 때, 크게 두 가지 방법으로 나눌 수 있을 것이다.

  1. [방법 1]과 같이 A객체 내부에서 new 키워드를 통해 B와 C 객체를 생성한 후 사용
  2. [방법 2]와 같이 외부에서 B와 C를 생성한 후, A객체에 주입을 시킨 후 사용

 

만약 프로세스가 변경되어 B와 C 객체가 아닌 B'와 C'로 변경이 되어야 한다면,

[방법 1]의 경우, A클래스와 B, C클래스는 강하게 결합되어 있기에 코드 수정에 있어서 보다 많은 자원이 낭비될 것이다.

반면 [방법 2]의 경우, B'와 C'만 주입하면 되기 때문에 [방법 1] 보다는 작업에 있어 적은 공수가 들 것이다.

그렇다면 의존성 주입은 어떻게 하는지 알아보자.

 

 

반응형

 

 

 

🌱 의존관계 주입 방법

의존관계 주입에는 크게 3가지 방법이 있다.

  1.  필드 주입
  2.  수정자 주입(= Setter 주입)
  3.  생성자 주입

 

1. 필드 주입

- 필드주입은 스프링 초장기부터 많이 사용되는 형태로 아래와 같이 코드가 간결하다는 장점이 있다.

   하지만 외부에서 변경이 불가능하여 테스트하기 힘들다는 단점이 있다.

- DI 프레임워크에 의존적이고 객체지향적인 관점에서 좋지 않다.

@Controller
public class Controller {

  @Autowired 
  private Service service;
  
}

 

 

2. 수정자 주입

- setter라 불리는 수정자 메서드를 통해서 의존관계를 주입하는 방법이다.

- 수정자 주입을 사용하면 setXXX 메서드를 public으로 열어두어야 하기 때문에 언제 어디서든 변경이 가능하다.

   이러한 성격 때문에 간혹 다른 곳에서 다시 주입을 하게 된다면 예기치 않은 오류를 발생시킬 수도 있다.
- 선택, 변경 가능성이 있는 의존관계에 사용된다. 

@Controller 
public class Controller {

   private Service service;

   @Autowired 
   public setService(Service service) {
     this.service = service; 
   }
   
}

 

 

3. 생성자 주입

- 생성자에 @Autowired를 붙여 의존관계를 주입하는 방법이다.
- 생성자 호출시점에 딱 한 번만 호출되는 것을 보장할 수 있다.

- 불변, 필수 의존관계에 사용된다.

@Controller 
public class Controller {

   private final Service service;

   @Autowired 
   public Controller(Service service) {
     this.service = service; 
   }
   
}


- 만약, 생성자가 딱 1개만 있다면 @Autowired를 생략할 수 있으며, 아래와 같은 코드로 변경 가능하다.

@Controller 
public class Controller {

   private final Service service;

   public Controller(Service service) {
     this.service = service; 
   }
   
}


- 또한 롬복을 사용하여 @RequiredArgsConstructor 어노테이션을 사용한다면, 아래와 같이 코드를 더욱 간결하게 줄일 수 있다.

@Controller
@RequiredArgsConstructor
public class Controller {

    private final Service service;
   
}

 

 

 

🌱 정리

Spring은 의존성 주입을 도와주는 DI 컨테이너로써, 
강하게 결합된 클래스들을 분리하고, 애플리케이션 실행 시점에 객체 간의 관계를 결정해 줌으로써 결합도를 낮추고 유연성을 확보해 준다.

이러한 특성 덕분에 다음과 같은 이점을 가져갈 수 있다.

  • 코드의 재사용성, 유연성이 높아진다. 
    - 하나의 작업만 수행하는 최소 단위의 객체는 상황에서 따라 쉽게 재결합하고 재사용할 수 있기 때문이다.
  • 객체 간 결합도가 낮기 때문에 한 클래스를 수정했을 때, 다른 클래스도 수정해야 하는 상황을 막아준다.
  • 유지보수가 쉬워지며, 테스트가 용이해진다.
  • 확장성을 가진다.

 

 

References.

1. https://caffeineoverflow.tistory.com/13
반응형

'IT' 카테고리의 다른 글

[Java] 자바 개발환경 준비 - JDK 설치 및 환경변수 설정  (1) 2025.01.18
[Spring] 스프링 IoC  (2) 2025.01.18
[IntelliJ] 인텔리제이 단축키 모음  (2) 2025.01.18
[Spring] 스프링 MVC  (1) 2025.01.18
[Spring] 스프링 개요  (4) 2025.01.18