스프링 DI에는 세 가지 방식이 있다.
이 중에서 필드 주입이 사용하기 가장 간단하지만, 생성자 주입을 사용하라고 권장되고 있다. 참고
세 가지 모두 테스트 해 볼 것이다.
Market이라는 클래스를 만들고, 마켓에서 판매할 상품인 고기와 야채, 스낵 클래스를 주입하는 테스트를 해볼 것이다. Lombok과 spring-test 라이브러리를 이용할 것이다. 📖스프링 설정 참고
마켓에서 판매할 고기와 야채를 클래스로 정의한다.
@Component
@ToString
public class Vegetable {
}
@Component
@ToString
public class Snack {
}
@Component
@ToString
public class Meat {
}
간단히 테스트만 할 것이므로 다른 코드는 작성하지 않았다.
@Component는 해당 클래스를 빈으로 등록하겠다고 명시하는 것이다.
마켓이라는 클래스를 정의하고 고기와 야채, 스낵을 멤버로 선언한다.
package com.coco.sample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@Getter
@ToString
@RequiredArgsConstructor
public class Market {
//필드 주입
@Autowired
private Meat meat;
//set 메서드 주입
@Setter(onMethod_ = {@Autowired})
private Vegetable vegetable;
//생성자 주입
private final Snack snack;
}
Market클래스에서 Meat, Vegetable을 선언만 하고 초기화는 하지 않았다.
대신 각각 @Autowirted를 붙였을 뿐이다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
@Log4j
public class MarketTest {
@Autowired
private Market market;
@Test
public void testExist() {
assertNotNull(market);
log.info(market);
log.info(market.getMeat());
log.info(market.getVegetable());
log.info(market.getSnack());
}
}
결과는?
INFO : com.coco.sample.MarketTest - Market(meat=Meat(), vegetable=Vegetable())
INFO : com.coco.sample.MarketTest - Meat()
INFO : com.coco.sample.MarketTest - Vegetable()
INFO : com.coco.sample.MarketTest - Snack()
테스트 클래스에서도 Market클래스를 멤버로 선언만 하고, 초기화는 하지 않았다. 그럼에도 불구하고 정상적으로 객체가 생성되었고, Market클래스에 선언만 해뒀던 Meat,Vegetable,Snack 객체 모두 생성된 것을 확인할 수 있다. 이것이 의존성 주입이다.
생성자 주입을 권장하는 이유는, 객체 생성 시에 의존성 주입이 이루어지므로 좀 더 엄격하게 의존성 주입을 체크한다는 장점이 있다.
@RequireArgsContructor
를 이용해서 단일 생성자의 묵시적 자동 주입 기능을 이용했다. 직접 생성자를 만들어서 @Autowired
를 붙여도 상관은 없다.
@RequireArgsConstructor
는 @NonNull
또는 final
이 붙은 인스턴스들의 생성자를 만들어주는 Lombok의 어노테이션이다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
@Log4j
@RunWith
@ContextConfiguration
@Log4j
스프링 컨텍스트 생성
프로젝트가 실행되면 가장 먼저 스프링 컨텍스트가 생성된다.
스프링 컨텍스트는 root-context.xml 또는 xml을 대체하는 설정 클래스 읽어서 자신이 스캔해야 할 패키지를 찾는다.
ComponentScan(basePackages = {"com.coco.sample"})
지정한 패키지의 클래스들 중에서 @Component가 붙은 클래스만 스프링의 Bean으로 등록한다.
스프링 컨텍스트는 Bean으로 등록된 클래스들만 관리한다.
스프링 컨텍스트는 빈을 관리하면서, 필요하다는 요청(@Autowired)을 받으면 알맞은 빈을 찾아서 주입한다.