TIL

의존관계 주입(DI)

류정근 2024. 5. 27. 23:22
의존관계 주입!! 이해라도 해보자!!!!

 

 

의존관계 주입 방법을 나누면 크게 4가지가 있다.

 

● 생성자 주입

  수정자 주입(setter 주입)

필드 주입

일반 메서드 주입

 

 

생성자 주입

생성자를 통해서 의존 관계를 주입 받는 방법

 

특징

1.생성자 호출시점에 1번만 호출되는 것이 보장된다.

2.불변,필수 의존관계에 사용

@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}

※ 생성자가 딱 1개만 있으면 @Autowired를 생략해도 자동 주입된다. (스프링 빈에만 해당)

 

 

수정자 주입(setter 주입)

setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입하는 방법

 

특징

1.선택, 변경 가능성이 있는 의존관계에 사용

 

@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}

※ @Autowired 의 기본 동작은 주입할 대상이 없으면 오류 발생, 주입할 대상이 없어도 동작하게 하려면 

  @Autowired(required = false) 로 지정해 주어야 함

 

필드 주입

필드에 바로 주입하는 방법

 

특징

1.코드가 간결해 보이지만 외부에서 번경이 불가능해서 테스트하기 힘듦

2.DI 프레임워크가 없으면 아무것도 할 수 없다.

3.사용하지 않는 것이 좋음

@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
```

  @SpringBootTest 처럼 스프링 컨테이너를 테스트에 통합한 경우에만 가능하다.

 

 

메서드 주입

일반 메서드를 통해서 주입 받는 방법

 

특징

1.한번에 여러 필드를 주입 받을 수 있음,

2,일반적으로 잘 사용하지 않음.

@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
```

※ 의존관계 자동주입은 스프링 컨테이너가 관리하는 스프링 빈이어야 동작한다. 스프링 빈이 아닌 클래스에서는 @Autowired 코드를 적용해도 아무 기능도 동작하지 않는다.

 

 

 

생성자 주입을 사용하자!!!

 

과거에는 수정자 주입과 필드 주입을 많이 사용했지만, 최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자 주입
을 권장한다.

 

생성자 주입이 좋은 이유

1.불변

대부분의 의존관계 주입은 한번 실행되면 변경할 일이 없다(오히려 변하면 안된다)

수정자 주입을 사용하면, set 메서드를 public으로 열어 두여야한다.(변경하면 안되는 메서드를 열어두는 것은 좋지 않은 설계 방법이다.)

●생성자 주입은 객체를 생성할 때 딱 1번만 호출되므로 이후에 호출되는 일이 없다. 따라서 불변하게 설계할 수 있다.

 

2.누락

 

수정자 의존관계에서 자바 코드를 단위 테스트 하는 경우

public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
//...
}

※  @Autowired 가 프레임워크 안에서 동작할 때는 의존관계가 없으면 오류가 발생하지만, 지금은 프레임워크 없
이 순수한 자바 코드로만 단위 테스트를 수행하고 있다.

 

@Test
void createOrder() {
OrderServiceImpl orderService = new OrderServiceImpl();
orderService.createOrder(1L, "itemA", 10000);
}

이렇게 테스트를 하면 실행은 되지만 NPE(Null Point Exception) 이 발생 하는데 memberRepository, discountPolicy 모두
의존관계 주입이 누락되었기 때문이다.

 

생성자 주입을 사용하면 다음처럼 주입 데이터를 누락 했을 때 컴파일 오류가 발생한다.

 

3.final 키워드

생성자 주입을 사용하면 필드에 `final` 키워드를 사용할 수 있다. 그래서 생성자에서 혹시라도 값이 설정되지 않는 오
류를 컴파일 시점에 막아준다.

※  수정자 주입을 포함한 나머지 주입 방식은 모두 생성자 이후에 호출되므로, 필드에 `final` 키워드를 사용
할 수 없다. 오직 생성자 주입 방식만 `final` 키워드를 사용할 수 있다.

'TIL' 카테고리의 다른 글

Token,RefreshTokebn 만들기  (0) 2024.06.03
JWT(JSON Web Token) 사용하기  (4) 2024.05.31
스프링 컨테이너와 빈  (0) 2024.05.23
좋은 객체 지향 설계의 5가지 원칙(SOLID)  (0) 2024.05.22
스프링 이란  (0) 2024.05.20