의존 관계 주입(생성자? 필드?)

전홍영·2023년 4월 22일
0

Spring

목록 보기
14/21
post-custom-banner

의존 관계 주입(DI)

스프링의 핵심 개념인 DI는 Dependency Injection으로 의존 관계 주입을 말한다. 의존관계 주입은 어플리케이션 실행 시 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결 되는 의존관계 주입이라 한다.

의존관계 주입을 사용하면 클라이언트 코드를 변경하지 않고, 클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다. 따라서 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

예를 들어 보면 Spring의 경우 CallServiceImpl 클래스가 MemberRepository와 PhoneRepository를 의존할 때 MemberRepository와 PhoneRepository의 구현체는 알 필요가 없다. 어플리케이션 실행 자동으로 스프링 컨테이너에서 객체가 자동 주입된다. 이것을 DI라 한다. 이렇게 서버(여기서 spring)이 프로그램을 관리하기 때문에 이것을 IoC(제어의 역적)이라고도 한다.

다양한 의존 관계 주입

생성자 주입

생성자를 통해 의존 관계를 주입 받는다.
생성자 주입을 하면 다양한 장점이 있는데 생성자 호출 시점에 딱 한번만 호출되고 객체가 생성된 후 변경할 수 없기 때문에 안정성을 보장한다. 또한 테스트에 용이하며, 컴파일시 오류를 바로 알 수 있다.

따라서 객체가 변화하면 안되는 경우 거의 대부분의 경우에 쓰인다.

@Component
public class CallServiceImpl implements CallService {
	
    private final MemberRepository memberRepository;
    
   	private final PhoneRepository phoneRepository;
    
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, PhoneRepository phoneRepository) {
    	this.memberRepository = memberRepository;
        this.phoneRespository = phoneRepository;
    }
}

수정자 주입(setter 주입)

setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입한다.
수정자를 통해 의존관계를 주입하게 되면 변경 및 수정에 용이하다.

@Component
public class CallServiceImpl implements CallService {
	
    private MemberRepository memberRepository;
    
   	private PhoneRepository phoneRepository;
    
    @Autowired(required = false) //자동 주입할 대상이 없으면 수정자 메소드가 작동하지 않는다.
    public setMemberRepository(MemberRepository memberRepository) {
    	this.memberRepository = memberRepository;
    }
    
    @Autowired
    public setPhoneRepository(@Nullable PhoneRepository phoneRepository) {//@Nullable은 자동주입할 대상이 없으면 null이 주입된다.
    	this.phoneRepository = phoneRepository;
    }
}

필드 주입

필드를 통해 바로 의존관계를 주입한다.
따로 생성자나 수정자를 작성하지 않아도 된어 코드가 짧아지고 간결해진다. 그러나 외부에서 변경이 불가능하여 테스트가 어렵다. 또한 DI 프레임워크가 없으면 실행되지 않는다.
부득이한 경우가 아닌 이상 필드 주입은 사용하지 않는 것이 좋다

@Component
public class CallServiceImpl implements CallService {

	@Autowired
    private MemberRepository memberRepository;
    
    @Autowired
   	private PhoneRepository phoneRepository;
}

일반 메서드 주입

일반 메소드를 통해 주입받는다.
이 방식은 많이 사용하지 않는다. 한 번에 여러 필드를 주입받는다.

@Component
public class CallServiceImpl implements CallService {

    private MemberRepository memberRepository;
    

   	private PhoneRepository phoneRepository;
    
    @Autowired
    public void init(MemberRepository memberRepository, PhoneRespository phoneRespository){
    	this.memberRepository = memberRepository;
        this.phoneRepository = phoneRespository;
    }
}

생성자 주입을 사용하자!

생성자 주입이 가장 안전하고 테스트가 용이하기 때문에 이를 스프링이나 DI 프레임워크에서는 권장하는 의존관계 주입 방법이다. 생성자 주입은 final 키워드를 사용할 수 있어 한 번 객체가 생성되면 변경이 불가하고 초기화가 되지 않으면 오류를 발생하기 때문에 컴파일시 초기화가 누락되면 오류를 발생시켜 런타임 오류를 방지한다.

profile
Don't watch the clock; do what it does. Keep going.
post-custom-banner

0개의 댓글