Published 2023. 5. 13. 23:15
들어가며
- 이번 포스트부터는 스프링 프레임워크가 @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컨테이너와 꽤 비슷하다.
1. 컴포넌트 스캔 수행
- 먼저 스프링 앱이 실행되면 @Component 어노테이션이 달려있는 모든 클래스를 스프링 빈으로 등록한다.
- 이때 스프링 빈 이름은 해당 클래스의 이름에서 맨 앞글자만 소문자로 변경시킨 이름이 디폴트이다.
- 만약 다른 이름을 설정하고 싶다면 @Component("componentName")으로 이름을 부여할 수 있다.
2. @Autowired를 통한 의존관계 자동 주입
- 이때 생성자에 @Autowired가 존재하는 경우, 스프링 컨테이너가 자동으로 필요한 스프링 빈을 찾아서 꽂아준다.(주입한다.) 이때 디폴트 설정은 타입이 동일한 스프링 빈을 찾아서 주입시킨다.
- 만약 Setter를 사용한 의존성 주입 방식에서 @Autowired를 달아놓았다면, 컴포넌트 스캔을 통해 모든 객체가 스프링 빈에 등록되고 난 이후에 별개의 스테이지에서 의존관계 자동 주입이 일어난다.
- 하지만 Constructor를 사용한 의존성 주입 방식은 스프링 컨테이너가 스프링 빈을 등록할 때 같이 일어난다는 사실을 유의하자(객체가 생성되기 위해서는 Constructor를 반드시 호출해야 하기 때문이다.)
정리
- 이번 포스트에서는 컴포넌트 스캔과 의존관계 자동 주입에 대해 알아보았다.
- 다음 포스트에서는 컴포넌트 스캔의 시작 위치와 스캔 범위에 대해 알아보고, 특정한 컴포넌트를 컴포넌트 스캔 대상에서 제외하는 방법인 필터에 대해서도 알아본다.
- 추가로, 컴포넌트 스캔에서 동일한 이름의 스프링 빈이 등록되는 상황에서 스프링 컨테이너는 어떻게 동작하는지에 대해서도 살펴보도록 한다.
'Spring & JPA > Spring' 카테고리의 다른 글
Spring Framework - 의존관계 자동 주입 - 1. 의존관계 주입 방법 (1) | 2023.05.17 |
---|---|
Spring Framework - 컴포넌트 스캔 - 2. 컴포넌트 스캔 위치, 대상, 필터 (0) | 2023.05.15 |
Spring Framework - 스프링과 Singleton - 3. Configuration (0) | 2023.05.12 |
Spring Framework - 스프링과 Singleton - 2. 싱글톤 컨테이너 (0) | 2023.05.10 |
Spring Framework - 스프링과 Singleton - 1. Singleton (0) | 2023.05.09 |