고딩왕 코범석

의존관계 주입(Dependency Injection) 본문

Language & Framework/Spring

의존관계 주입(Dependency Injection)

고딩왕 코범석 2020. 11. 19. 20:07
반응형

본 포스팅은 스프링 핵심 원리 - 기본편 (김영한 님) 강좌 내용을 복습하는 포스팅입니다. 지적은 환영해요!

스프링에는 다양한 의존주입 방법이 있다. 대표적으로 생성자, setter, 필드, 일반 메서드 주입 이렇게 총 네가지가 있는데 하나씩 살펴보도록 하자.

1. 생성자 주입

생성자 주입은 해당 클래스에 생성자에 의존관계를 주입하는 방법으로써

public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
}

요롬코롬 작성할 수 있겠다. 참고로 @Autowired는 의존관계를 자동 주입하기 위한 애노테이션으로 스프링을 써봤다면 누구나 아는 애노테이션..! 나중엔 이걸 롬복을 활용하여 없앨 수 있다.


특징은 불변, 필수 의존관계에 꼭 사용하며 생성자 호출시점에 딱 한번만 호출되는 것을 보장한다!! 그래서 자바의 final 키워드를 이용하여 해당 빈을 등록하고 필요한 의존관계를 맨 처음에만 주입하고 그 이후에는 DI 컨테이너가 관리하게 끔 만들어준다. 대부분 이 주입방법을 사용한다!


참고로 해당 클래스 내에 생성자가 단 하나만 존재한다면 @Autowired를 생략해도 된다!


왜 생성자 주입을 사용해야하는가 ?

  • 생성자 주입은 딱 한번만 실행되므로 이후에 호출될 일이 없다. 따라서 불변하게 설계할 수 있다.
  • setter 메서드를 public으로 열어둘 경우 결국에는 누군가 setter 메서드를 실행시킬 수 있다. 아예 막아버리자
  • 만약 단위테스트를 하는 경우에 setter 의존 주입을 선택한 경우, 테스트 작성시 NPE이 발생한다.
  • final 키워드 사용이 가능하다! 혹시라도 값이 설정되지 않는 오류를 컴파일 에러를 통해 직접 막아줄 수 있다!!!

2. setter 주입

setter 주입은 setter메서드에 @Autowired 애노테이션을 붙여 의존관계를 주입하는 방법이다.

public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository;

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
}

이렇게 말이지!
단! 생성자 주입과는 차이점이 있다!

DI 컨테이너에서 빈들을 생성자를 이용하여 등록할 때, 생성자 주입을 통해 의존관계가 주입이 된다. 즉, 빈을 등록하면서 알아서 의존관계가 주입된다!
하지만, setter 주입의 경우는 생성자로 인해 스프링 컨테이너에 빈 등록이 다 되었을 경우, 스프링 빈 의존관계 설정시에 일어난다는 차이점이 있다.

특징은 선택적, 변경 가능성이 있는 의존관계를 주입시 사용한다.


선택적으로 의존관계를 주입할 경우에는 @Autowired(required = false) 옵션을 주어 설정할 수 있다! 만약에 @Autowired 애노테이션만 해놓고 의존주입을 하지 않을 경우 에러가 발생한다! @Autowired의 required값 default는 true니깐!
변경을 할 경우에는 setter 메서드에서 바꿀 수 있지만 거의 없다고 그러셨다...!

3. 필드 주입

해당 클래스의 필드부분에 @Autowired를 하는 방법이다.

public class MemberServiceImpl implements MemberService{

    @Autowired
    private MemberRepository memberRepository;

}

이렇게!
하지만 외부에서 변경할 수 없으므로 테스트를 할 경우 굉장히 불편하다! 또 DI 프레임워크가 없다면 아무것도 할 수 없다...
즉, 순수한 자바 자체로 테스트를 할 수 없다는 말이다...

예를 들어, 해당 Service를 테스트하고 싶은데 Repository 부분을 다른 것으로 바꾸고 싶다면 바꿀 수 없다... 결국 setter메서드를 열어서 밖에!
쓰지말자
테스트 코드 내에서 의존주입을 받을 경우에만 사용한다!

4. 일반 메서드 주입

이 부분은 새롭게 안 사실인데, 사실 @Autowired는 아무데서나 쓸 수 있다!

public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository;

    @Autowired
    public void init(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
}

엥 메서드명만 다르지 setter랑 똑같네??

한번에 여러 필드를 주입받을 수 있지만, 일반적으로 잘 사용하지 않는다.


꼭 명심하긔. 의존주입은 꼭 스프링 빈일때만 적용된다는 것을... 당연히 스프링이 관리하는 빈들이 자동주입 되는거니깐! @Component, @Service, @Repository, @Controller 에서!

옵션 설정

하지만 스프링 빈으로 등록되지 않더라도 동작해야 할 경우도 있다. 그 경우에 할 수 있는 방법을 세가지 알아보자.

  • @Autowired(required = false)

  • @Nullable 활용

  • Optional 활용



    다음 코드를 보자.

    class TestBean{
    
          @Autowired(required=false)
          public void setNoBean1(Member member){
              System.out.println("member = " + member);
          }
    
          @Autowired
          public void setNoBean2(@Nullable Member member){
              System.out.println("member = " + member);
          }
    
          @Autowired
          public void setNoBean3(Optional<Member> member){
              System.out.println("member = " + member);
          }
      }
  1. @Autowired(required = false)
    해당의 경우 스프링 빈으로 등록될 때, 아예 호출되지 않는다!

  2. @Nullable
    해당의 경우 스프링 빈으로 등록될 때, null이 그대로 호출된다.

  3. Optional
    해당의 경우 스프링 빈으로 등록될 때, Optional.empty로 출력된다. null을 안전하게 Optional로 감쌌다고 보면 된다. 이 덕에 java 8 버전 문법도 배워야겠다는 생각이 든다ㅠㅠ






오늘은 여기까지! 지적은 환영해요ㅠㅠ

반응형

'Language & Framework > Spring' 카테고리의 다른 글

@Async, 비동기 기능  (0) 2021.02.16
ResponseEntity란?  (4) 2021.02.08
JUnit과 계층별 단위 테스트 정리  (0) 2021.01.31
트랜잭션에 대해 알아보자.  (0) 2020.11.28
DTO란?  (0) 2020.10.30