suyeonme

[Spring] Dependency Injection(DI), Dependency Lookup(DL)이란? 본문

프로그래밍👩🏻‍💻/Spring

[Spring] Dependency Injection(DI), Dependency Lookup(DL)이란?

suyeonme 2022. 6. 5. 11:31

1. Dependency Injection(DI)이란?

스프링 컨테이너가 스프링 빈(bean)간의 의존 관계를 외부에서 주입해주는 것을 말한다.

의존 관계 주입을 하기 위해서는 먼저 스프링 컨테이너에 스프링 빈으로 등록해야한다.

 

스프링에서 제공하는 DI를 사용하지 않으면, 개발자가 직접 의존 관계가 있는 클래스들을 new 키워드를 사용하여 일일이 연결해야하는데 이는 매우 번거롭다.

// new 키워드 사용
public class MemberService {
  private MemberService memberRepository = new MemberRepository();
}

// 스프링의 DI 사용
@Service
public class MemberService {
    private final MemberRepository memberRepository;
    
    @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

2. DI(Dependency Injection)를 하는 방법

클래스 의존 관계 주입은 constructor -- setter -- method 순으로 호출된다.

 

1. 생성자 주입

  • 클래스 생성시에 생성자를 통해서 의존 관계를 주입한다. 그 이후에는 변경이 불가능하여 가장 안전하다.
  • 생성자가 1개인 경우, @Autowired는 생략할 수 있다.
  • 대부분 경우, 생성자 주입 방식이 사용된다.
private final MemberRepository memberRepository;

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

2. setter 주입

  • 변경 가능성이 있는 의존 관계에 사용한다.
  • 외부에 노출이 되기 때문에 문제가 발생했을 때, 디버깅이 어려울 수 있다.
private final MemberRepository memberRepository;

@Autowired
public void setMemberService(MemberService memberRepository) {
  this.memberService = memberRepository;
}

3. field 주입

  • 코드는 간결하지만, 외부에서 변경이 불가능하여 테스트가 어렵다.
  • 비추천
@Autowired private MemberRepository = memberRepository;

4. 일반 메서드(method) 주입

  • 한번에 여러 필드를 주입받을 수 있다.
  • 비추천
private MemberRepository memberRepository;

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

5. Lombok 라이브러리를 이용하여 주입

  • Lombok 라이브러리에서 제공하는 @RequiredArgsConstructor 애노테이션을 사용한다.
  • 라이브러리가 내부적으로 생성자를 생성해주기 때문에 코드가 간결해진다. 생성자를 통해 의존성 주입을 하는 코드를 작성하지 않아도 된다.
@RequiredArgsConstructor
public class TestClass {
  private final MemberRepository memberRepository;
}

 @ Autowired

  • @AutoWired는 빈(Bean) 클래스에서만 작동한다.
  • @AutoWired는 주입할 대상이 없으면 오류가 발생한다. 따라서 주입할 대상이 없어도 동작하게 하려면 @AutoWired(required = false)로 지정해야한다.
  • @Autowired는 클래스의 타입(type)으로 빈(bean)을 조회한다.

 

 3. Dependency Lookup(DL)

Dependency Injection(DI)에 반대되는 개념으로, 의존관계를 외부에서 주입받는 것이 아니라 직접 필요한 의존 관계를 주입하는 것을 의미한다. 대표적으로 Provider를 통한 의존 관계 주입이 있다.

 

대표적인 provider 종류는 아래와 같다.

3.1 ObjectProvider, ObjectFactory

  • ObjectProvider.getObject()은 스프링 컨테이너(ApplicationContextBean)에서 특정 빈(bean)을 찾아서 반환한다.
  • ObjectProvider.getObject()를 호출하면, 호출 시점까지 빈(bean)의 생성을 지연한다.
  • ObjectFactory에 편의 기능이 추가된 것이 ObjectProvider(신규)이다.
  • 스프링에서 제공하는 provider이기 때문에 스프링에 의존적이다.
public class ClientBean {
  @Autowired
  private ObjectProvider<PrototypeBean> prototypeBeanProvider;

  public int init() {
    PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
    prototypeBean.addCount();
  }
}

3.2 JSR-330 Provider

  • javax.inject:javax.injec:1 라이브러리를 dependency에 추가한다. (JSR은 자바 표준을 의미한다.)
  • JSR에서 제공하는 Provider.get() 메서드를 사용한다.
  • 자바 표준이므로 스프링이 아닌 다른 컨테이너에서도 사용이 가능하다.
public class ClientBean {
  @Autowired
  private Provider<PrototypeBean> prototypeBeanProvider;

  public int init() {
    PrototypeBean prototypeBean = prototypeBeanProvider.get();
	prototypeBean.addCount();
  }
}
Comments