백엔드/Spring

[Spring] 스프링 의존관계 주입 방식의 종류와 생성자 주입 방식을 사용해야 하는 이유

happy_life 2022. 5. 3. 18:27

스프링 의존관계 주입 방식의 종류와 생성자 주입 방식을 사용해야 하는 이유

목차

  1. 의존관계 주입이란?
  2. 의존관계 주입 방법의 종류
  3. 생성자 주입을 사용해야 하는 이유

 

1. 의존관계 주입이란?

의존관계 주입 DI(Dependency Injection)

의존관계는 정적인 클래스 의존관계, 실행 시점에 결정되는 동적인 객체 의존 관계로 구분 된다.

 

정적인 클래스 의존관계

구현과 역할 그리고 의존으로 나뉜 정적인 클래스 의존관계를 의미한다. 예를 들어 아래의 코드를 보면 MemberServiceImpl은 MemberRepository에 의존한다는 것을 알 수 있다. 하지만 이런 클래스 의존 관계 만으로는 실제 어떤 객체가 MemberServiceImpl에 주입되는지 알 수 없다. 

(MemberRepository의 구현체인 MmoryMemberRepository, DbMemberRepository 중 어느 것이 주입되는지 알 수 없다.)

 

public class MemberServiceImpl implements MemberService{

    //추상화에만 의존하게됨
    private final MemberRepository memberRepository ;

     
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

 

클래스 다이어그램

동적인 객체 인스턴스 의존관계

애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존관계를 의미한다.

 

객체 다이어그램

 

 

2. 의존관계 주입 방법의 종류

1. 생성자 주입 방식

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

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

 

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

public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository ;

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

 

2. 수정자 주입 방식(setter 주입)

특징 : 선택, 변경 가능성이 있는 의존관계에 사용한다.

public class MemberServiceImpl implements MemberService{

    private MemberRepository memberRepository ;

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

 

3. 필드 주입 방식

특징: 코드가 간결하지만, DI 프레임워크가 없으면 아무것도 할 수 없다. 사용하지 말것

public class MemberServiceImpl implements MemberService{
	@Autowired
    private MemberRepository memberRepository ;

}

 

4. 일반 메서드 주입 방식

public class MemberServiceImpl implements MemberService{
	
    private MemberRepository memberRepository ;
    
    @Autowired
    public void init(MemberRepository memberRepository){
    this.memberRepository = memberRepository;
    }
    
}

 

*참고

의존관계 자동 주입은 스프링 컨테이너가 관리하는 빈이어야 동작한다. (@Autowired 라는 어노테이션을 사용하려면 스프링 커네이너가 관리하는 스프링 빈 객체여야한다.)

 

 

3. 생성자 주입을 사용해야 하는 이유

 

불변

1. 대부분의 의존관계 주입은 한번 일어난 후 애플리케이션이 종료될 때까지 의존관계를 변경할 일이 없다. 오히려 애플리케이션 종료 전까지 변하면 안된다.

 

2. 수정자 주입을 사용하면 set 메서드를 public으로 열어두어야하는데, 이렇게 되면 누군가 실수로 변경할 수 도있고, 변경하면 안되는 메서드를 열어두는 것은 좋은 설계 방법이 아니다.

 

 디버깅 용이성

1. 불변하는 것이므로 final을 선언해 주게 되는데 만약 생성자 주입 코드에 실수로 코드를 작성하지 않았을 경우 컴파일 오류로 빠르게 해결할 수 있게 된다.

 

2. test 코드 작성시 생성자를 누락하는 경우에도 컴파일 오류로 빠르게 해결할 수 있게 한다.

set 메소드를 사용하면 들어가는 인자가 무엇이었는지 기억나지 않는 경우 해결하기가 어렵다.

스프링 의존관계 주입 방식의 종류와 생성자 주입 방식을 사용해야 하는 이유