요르딩딩

[Personal_Project] DI (필드, 수정자, 생성자)주입방법 (7) 본문

[Personal_Project]

[Personal_Project] DI (필드, 수정자, 생성자)주입방법 (7)

요르딩딩 2021. 5. 3. 17:48
728x90
반응형

이번시간에는 DI(의존성 주입)에 대해서 공부해보겠습니다.

 

스프링의 가장 기본적인 능력은 객체를 생성하고 조립하는 능력입니다. 이때 사용되는 용어가 DI, IoC입니다.

DI는 의존성 주입으로 '부품 조립'이라고 생각하시면 될거 같습니다. 이러한 '부품 조립'방식은 결합을 느슨하게 하여, 부품을 갈아끼운다거나 업데이트를 보다 편리하게 해줍니다. 일체형방식이라면 내용을 잘 모르고, 교체하기도 어렵습니다.

 

조립하는 것이 어렵지만 '조립을 해주는 서비스'를 이용하면 됩니다. 이것이 바로 스프링입니다.

스프링의 xml파일과 Annotation이 부품의 주문서 역할을 합니다. 주문서 대로 부품을 담을 공간을 '컨테이너'라고 합니다.

 

하지만 이것을 IoC라고 부르는 이유가 있습니다. '제어반전'으로 일체형 객체생성는 A-B-C-D처럼 순차적으로 생성됩니다.

A를 생성하면 나도 모르게 나머지도 생성되는 것입니다.

그러나 결합형의 순서는 반대입니다. D가 만들어지고, C가 만들어지고 결합, B가 만들어지고 결합하여 A가 생성되는 방식입니다.

이렇게 조립에 대한 순서가 역순으로 객체를 생성하기 때문에 '제어반전'이라고 부릅니다.

 

DI(의존성 주입)은 크게 3가지 방법이 있습니다.

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

1. 필드 주입 (Field Injection)

@Service
public class bankService{

   @Autowired
   private DepositeService depositeService;
   
   @Autowired
   private withdrawService withdrawService;
}

[단점]

  1. 코드가 간결하지만, 외부에서 변경이 불가능해 테스트하기 힘들다는 단점이 큽니다.
  2. DI 프레임워크가 없으면 아무것도 할 수 없습니다.

[참고] 

일반 자바 테스트코드에서는 당연히 @Autowired가 동작하지 않습니다. > 스프링컨테이너를 테스트에 통합한 경우에만 가능합니다.

2. 수정자 주입 (Setter Injection)

@Service
public class bankService{
   
   private dipositeService depositeService;
   private withdrawService withdrawService;
   
   @Autowired 
   public void setDepositeService(DepositeService depositService){
      this.depositeService = depositeService;
   }
   
   @Autowired 
   public void setWithdrawService(WithdrawService withdrawService){
      this.withdrawService = withdrawService;
   }
}

[단점]

  1. 대부분의 의존성 주입은 한번 일어나면 애플리케이션이 종료시점까지 의존관계를 변경할 일이 없습니다. > 대부분은 변하면 안됩니다.(불변) 그러나 수정자 주입은 누군가의 실수로 변경될 수 도 있고, 변경하면 안되는 메서드를 열어두기 때문에 좋은 설계방법이 아닙니다.
  2. 수정자 주입을 사용하면, setXxx메서드를 public으로 열어주어야합니다.

3. 생성자 주입 (Constructor Injection)

@Service
public class bankService{

   private final DepositeService depositeService;
   private final WithdrawService withdrawService;
   
   @Autowired //@Autowire는 생성자가 하나일 경우 생략가능.
   public bankService(DepositeService depositeService, WithdrawService withdrawService){
      this.depositeService = depositeService;
      this.withdrawService = withdrawService;
   }
}



[장점]

  1. 생성자 호출시점에 딱 1번만 호출합니다. (불변)
  2. 주입 데이터를 누락했을때 컴파일 시점에 컴파일 오류가 발생합니다.
  3. final키워드를 사용할 수 있습니다. (불변)
  4. 원하는 구현체를 주입할 수 있으며, 순수 자바 코드로 테스트를 할 수 있습니다. (프레임워크에 의존하지 않음)

이러한 장점들도 생성자 주입(Constructor Injection)을 사용하는것을 권장하고 많이 사용되고 있습니다.

 

[연습]

 

[commonController.java] 

[BankService.java] : interface

[BankServiceImpl.java]

   주의 : @Service추가, implements 추가, (생성자에 final 추가시 에러 > controller에서 생성자 적용시 final가능 : why??? 공부하자!!!)

[DepositeService.java] : interface

[DepositeServiceImpl.java]

 주의 : @Service추가, implements 추가

[WithdrawService.java] : interface

[WithdrawServiceImpl.java]

 주의 : @Service추가, implements 추가

[결과]

(+ 추가) 

pom.xml에 Junit관련 <dependency>를 추가한 후 단위테스트를 할 메소드위에 @Test를 추가하면 Junit 테스트가 가능하디.

현재 테스트시 객체생성이 되지 않음으로 NullPointException이 발생해 오류를 확인할 수 있다.

해당 부분에 대해서는 더 공부를 해보도록하자!!!

 

728x90
반응형
Comments