DI의 3가지 방법과 생성자 주입을 이용해야하는 이유

SeokHwan An·2023년 5월 2일
0

spring

목록 보기
3/3

DI(Dependency Injection) 의존성 주입은 스프링을 처음 사용하고 나서 부터 가장 많이 듣는 용어 중에 하나였습니다. 의존성 주입에서 의존성은 객체 사이의 발생하는 관계를 의미합니다. 객체가 협력하는 세상에서는 객체간의 의존성을 항상 존재하고 이를 잘 관리하는 것이 중요합니다.

스프링에서는 스프링 빈을 통해서 DI를 제공하며 그 이유는 다음과 같습니다.

  1. 개발자가 오로지 비즈니스 로직에 신경 쓰게 해준다. 즉 관심사의 분리입니다.
  2. 객체간의 의존성을 직접 코드가 아닌 외부에서 주입해줌으로써 코드의 재사용성을 높이고 객체간의 결합을 낮출 수 있습니다.

의존성을 주입할 수 있는 방법은 3가지로 생성자 주입, 필드 주입, setter 주입 이 있습니다.

생성자 주입

생성자 주입은 생성자를 통해서 의존관계를 주입하는 방법입니다.

@Component
public class Orchestra {
		
		private final TrumpetPlayer trumpetPlayer;
		private final FlutePlayer flutePlayer;
		private final ViolinPlayer violinPlayer;
		
		@Autowired
		public Orchestar(TrumpetPlayer trumpetPlayer, FlutePlayer flutePlayer, ViolinPlayer violinePlayer) {
				this.trumpletPlayer = trumpetPlayer;
				this.flutePlayer = flutePlayer;
				this.violinPlayer = violinPlayer;
		}
}

생성자 주입은 위의 코드 처럼 생성자의 @Autowired를 붙어서 이용하는 방식이지만 생성자가 하나만 있다면 @Autowired를 생략해도 생성자 주입을 적용시켜 줍니다. 하지만 다른 의존성 주입 방식에 비해 코드의 길이가 길지만 lombok을 이용하면 간결하게 처리할 수 있습니다.

@RequiredArgsConstructor
@Component
public class Orchestra {
		
		private final TrumpetPlayer trumpetPlayer;
		private final FlutePlayer flutePlayer;
		private final ViolinPlayer violinPlayer;
}

위의 코드 처럼 lombok의 @RequiredArgsConstructor 를 활용하면 private final 만 붙이면 생성자로 의존성을 주입할 수 있습니다.

생성자 주입의 장점은 다음과 같습니다.

  • 생성자 호출시점에 1번만 호출되는 것이 보장이 되어 객체가 변하지 않는다는 것을 보장할 수 있다.
  • 테스트가 용의하다. DI 컨테이너에 의존적이지 않다.

필드 주입

필드 주입은 필드에 의존관계를 주입하는 방법입니다.

@Component
public class Orchestra {
		
		@Autowired
		private TrumpetPlayer trumpetPlayer;
		
		@Autowired
		private FlutePlayer flutePlayer;

		@Autowired
		private ViolinPlayer violinPlayer;
		
}

이를 자바 코드로 변경하면 다음과 같다고 볼 수 있다.

public class Orchestra {
		
		private TrumpetPlayer trumpetPlayer = new TrumpetPlayer() ;	
		private FlutePlayer flutePlayer = new FlutePlayer();
		private ViolinPlayer violinPlayer = new ViolinPlayer();
		
}

필두 주입은 필드에 @Autowired를 붙여서 간단하게 의존관계를 주입할 수 있습니다. 하지만 필드 주입은 인텔리제이에서도 추천하는 방식이 아닙니다. 그 이유는 다음과 같습니다.

  • 테스트가 DI 컨테이너에 의존적이다.
  • 필드에 강한 의존성이 생긴다.
  • 객체의 유연성이 떨어진다.

세터 주입

세터 주입은 set 메서드를 이용해 의존성을 주입해주는 방법입니다.

@Component
public class Orchestra {
		
		private TrumpetPlayer trumpetPlayer;	
		private FlutePlayer flutePlayer;
		private ViolinPlayer violinPlayer;
		
		@Autowired
		public void setTrumpetPlayer(TrumpetPlayer trumpetPlayer) {
				this.trumpetPlayer = trumpetPlayer;
		}
		
		@Autowired
		public void setFlutePlayer(FlutePlayer flutePlayer) {
				this.flutePlayer = flutePlayer;
		}

		@Autowired
		public void setViolenPlayer(ViolenPlayer violenPlayer) {
				this.violenPlayer = violenPlayer;
		}
}

세터 주입은 set 메서드 위에 @Autowired를 붙여서 의존관계를 주입해주는 것이다. 이는 의존 관계의 변화가 일어날 때 이용하는 것이라고 하지만 아직까지는 경험을 해본적이 없어서 세터 주입이 필요한 것인지 잘 모르겠고 인텔리제이에서도 추천해주는 방식이 아닙니다.

  • public으로 set 메소드를 열어두는 것이기 때문에 외부에서 불필요하게 의존관계를 변경할 수 있다.

이와 같이 3가지 방식의 DI를 알아보았습니다. 저는 이를 정리하면서 생성자 주입을 이용하는 것이 좋다고 느꼈습니다. 이는 스프링의 DI를 이용했을 때 뿐만이 아니라 자바만을 이용해서 DI를 적용할 때도 마찬가지라고 생각합니다. 필드 주입은 객체간의 강한 의존성을 가지게 할 뿐만 아니라 DIP와 OCP를 위반하기 때문입니다. 그리고 setter 주입 방식은 외부에서 의존관계를 변경함으로써 객체의 불변을 보장하지 못하는 것이기에 좋지 않은 방식이라고 느꼈습니다.

0개의 댓글

관련 채용 정보