들어가며

  • 이번 포스트부터는 스프링 프레임워크가 @Bean으로 직접 수동으로 스프링 빈을 등록하지 않는 상태에서도 어떻게 객체들을 스프링 빈으로 등록하는지와 의존관계를 자동 주입하는 방법에 대해 알아본다.

 

 

컴포넌트 스캔

  • 컴포넌트 스캔은 스프링이 각 객체를 스캔하면서 @Component가 존재하는 클래스의 인스턴스들을 스프링 컨테이너에 적재시킨다.
  • 이를 수행하려면 다음과 같이 코드를 짜면 된다.
@Configuration
@ComponentScan
public class AutoAppConfig{

}
  • 코드를 보면 내부에 그 어떠한 코드도 없다. 심지어 @Bean으로 등록한 클래스들도 없다.
  • 이는 @ComponentScan 어노테이션을 발견했을 시에 스프링에서 자동으로 컴포넌트 스캔을 통해 @Component 어노테이션이 붙은 클래스들을 스프링 빈으로 처리하기 때문이다.
  • 이 컴포넌트 스캔의 대상이 되기 위해서는 클래스에 @Component를 붙이면 된다.
@Component
public class MemoryMemberRepository{
    private static Map<Long, Member> store = new HashMap<>();
    private static long seqNo = 0L;

    public Member save(Member member){
        member.setId(seqNo++);
        store.put(member.getId(), member);

        return member;
    }

    public Member findById(long id){
        return store.get(id);
    }

    public List<Member> findAll(){
        return new ArrayList<>(store.values());
    }

    public void clear(){
        store.clear();
    }
}
  • 이렇게 @Component 어노테이션만 붙였을 뿐인데도 @Configutaion 설정 파일에서 @Bean으로 객체를 생성하는 동작과 동일한 효과를 볼 수 있다.

 

 

의존관계 자동 주입

  • 스프링에서 DI를 자동으로 수행해주는 것은 이전의 여러 포스트를 통해서 알 수 있던 사실이다.
  • 그런데 이전까지는 우리가 AppConfig라는 Configuration을 통해서 지시해주었다면, 지금은 컴포넌트 스캔으로 인하여 저런 설정 파일에서 DI를 하도록 지시하는 코드가 없는 것을 알 수 있다.
  • 스프링에서는 이전에 의존관계를 주입하는 동작을 @Autowired 라는 어노테이션을 통해 동일하게 동작하도록 한다.
@Component
public class OrderServiceImpl implements OrderService{
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    
    @Autowired
    OrderService(MemberRepository memberRepository, DiscountPolicy discountPolicy){
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
    
    ...
}
  • 해당 코드를 보자. @Component가 있어 이 객체는 스프링 컨테이너에서 스프링 빈으로 생성될 것 이다.
  • 그런데 생성되는데에는 MemberRepository와 DiscountPolicy 타입의 객체가 필요하다. 이때 @Autowired를 통해 스프링이 스프링 컨테이너에서 해당 객체가 존재하는지를 찾고, 존재하는 경우 해당 객체를 가져와 DI를 수행한다.
  • 이후 OrderServiceImpl 객체가 생성되고, 스프링 컨테이너에 스프링 빈으로 등록된다.

 

 

 

컴포넌트 스캔과 자동 의존관계 주입의 과정

  • 스프링 앱이 실행될 때 어떻게 컴포넌트 스캔과 자동 의존관계가 주입되는지에 대해 간략하게 그림으로 설명한다.
  • 대략적인 그림은 이전 스프링 DI컨테이너와 꽤 비슷하다.
 

Spring Framework - Spring DI 컨테이너

들어가며 이전 글에서 IoC의 개념과 IoC 컨테이너(또는 DI 컨테이너)에 대해서 알아보았다. 스프링 프레임워크는 자체적인 DI 컨테이너를 가지고 있으며 런타임 시점에서 스프링 빈(Bean)으로 등록

sehun5515.tistory.com

1. 컴포넌트 스캔 수행

  • 먼저 스프링 앱이 실행되면 @Component 어노테이션이 달려있는 모든 클래스를 스프링 빈으로 등록한다.

  • 이때 스프링 빈 이름은 해당 클래스의 이름에서 맨 앞글자만 소문자로 변경시킨 이름이 디폴트이다.
  • 만약 다른 이름을 설정하고 싶다면 @Component("componentName")으로 이름을 부여할 수 있다.

2. @Autowired를 통한 의존관계 자동 주입

  • 이때 생성자에 @Autowired가 존재하는 경우, 스프링 컨테이너가 자동으로 필요한 스프링 빈을 찾아서 꽂아준다.(주입한다.) 이때 디폴트 설정은 타입이 동일한 스프링 빈을 찾아서 주입시킨다.
  • 만약 Setter를 사용한 의존성 주입 방식에서 @Autowired를 달아놓았다면, 컴포넌트 스캔을 통해 모든 객체가 스프링 빈에 등록되고 난 이후에 별개의 스테이지에서 의존관계 자동 주입이 일어난다.
  • 하지만 Constructor를 사용한 의존성 주입 방식은 스프링 컨테이너가 스프링 빈을 등록할 때 같이 일어난다는 사실을 유의하자(객체가 생성되기 위해서는 Constructor를 반드시 호출해야 하기 때문이다.)

 

 

 

정리

  • 이번 포스트에서는 컴포넌트 스캔과 의존관계 자동 주입에 대해 알아보았다.
  • 다음 포스트에서는 컴포넌트 스캔의 시작 위치와 스캔 범위에 대해 알아보고, 특정한 컴포넌트를 컴포넌트 스캔 대상에서 제외하는 방법인 필터에 대해서도 알아본다.
  • 추가로, 컴포넌트 스캔에서 동일한 이름의 스프링 빈이 등록되는 상황에서 스프링 컨테이너는 어떻게 동작하는지에 대해서도 살펴보도록 한다.
복사했습니다!