컴포넌트 스캔(Component Scan)
스프링 빈을 등록하기 위해 @Bean 어노테이션을 붙혀주거나
<bean>이라는 XML 태그를 붙혀서 직접 설정 정보에 스프링 빈을 등록했다.
하지만 이런 방식으로 계속 할 경우 빈이 엄청나게 많아지고 관리가 힘들어진다.
스프링은 이런 상황 때문에 컴포넌트 스캔을 제공한다.
@ComponentScan이라는 어노테이션을 통해서 해당 기능을 사용한다.
먼저 ComponetScan을 사용하기 전 코드를 살펴보자.
빈 수동 등록
빈 설정 클래스
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
수동 주입 클래스중 일부 클래스
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemoryMemberRepository memoryMemberRepository) {
this.memberRepository = memoryMemberRepository;
}
}
메인 클래스
public class MemberApp {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = ac.getBean("memberService", MemberService.class);
}
}
위 코드들을 보면 전 포스팅에서 알 수 있듯 AppConfig라는 클래스를 통해서 의존관계를 주입해주고 있다.
하지만 앞서 말했듯 클래스가 많아지고 등록해야 할 빈이 많아지면 작성해야 할 코드가 많아지고 관리가 힘들어진다.
ComponentScan 적용
이제 @ComponetScan을 적용해보자.
빈 설정 클래스
@Configuration
@ComponentScan
public class AppConfig {
}
의존관계 자동 주입 클래스중 일부 클래스
@Component
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
호출 클래스
public class MemberApp {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = ac.getBean("memberService", MemberService.class);
}
}
기존 코드와 달리 설정 클래스에는 아무런 코드 없이 @ComponentScan 어노테이션만 추가됐다.
그리고 주입이 필요한 다른 클래스에는 @Component를 추가해 주었고,
주입이 필요한 필드에는 @Autowired를 사용해 생성자 주입을 해주었다.
ComponetScan으로 의존성 주입이 가능한 이유
수동빈 등록과 달리
주입이 필요한 클래스에 Component 어노테이션을 붙여주면,
ComponentScan이 Component이 붙은 클래스를 탐색해서 자동으로 스프링 컨테이너에 빈을 등록해준다.
이전에 AppConfig에서는 @Bean 으로 직접 설정 정보를 작성했고, 의존관계도 직접 명시했다.
이제는 이런 설정 정보 자체가 없기 때문에, 의존관계 주입도 클래스 안에서 해결해야 하는데,
이 때 @Autowired 를 사용하면 의존관계를 자동으로 주입해준다.
(생성자가 하나일 경우 @Autowired를 생략할 수 있다.)
Component 클래스에 이름을 따로 지정해 주지 않으면 자동으로 맨 앞글자를 소문자로 바꿔서 이름을 지정해준다.
ex) MemberServiceImpl -> memberServiceImpl
중복 등록과 충돌
중복 등록엔 두 가지 경우가 있다
- 자동 빈 등록 vs 자동 빈 등록
- 컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
- 컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
- 수동 빈 등록 vs 자동 빈 등록
-
수동 빈 등록이 우선권을 가져 오버라이드 해버린다.
하지만 의도하지 않은 상황에서 이렇게 되면 잡기 어려운 애매한 버그가 발생한다.
그래서 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 만들어 두었다.
-
'스프링' 카테고리의 다른 글
Spring - MVC (0) | 2024.05.20 |
---|---|
Spring - Spring Container와 Dependency Injection (1) | 2024.04.11 |
스프링 시큐리티 defaultSecurityFilterChain (1) | 2023.12.20 |
스프링 시큐리티 내부 흐름 (1) | 2023.12.18 |
스프링 DI (0) | 2023.12.17 |