지금까지 빈을 등록하기 위해서 AppConfig class에 사용자가 일일히 @Bean으로 관리해주어야 했습니다. 하지만 이건 개발자에게 너무 귀찮은 작업이고 누락하게 되면 큰 장애가 발생하게됩니다. 그래서 Spring은 @Bean으로 일일히 등록하지 않아도 자동으로 스프링 빈으로 등록해주는 @ComponentScan과 @Component annotation을 제공합니다.
컴포넌트 스캔을 사용하게 되면 DI가 애매해집니다. 지금까진 수동으로 의존관계를 주입했지만 Bean이 자동으로 등록되게되니 의존관계를 설정할 수 있는 부분이 사라진것입니다. 그래서 @Autowired annotation을 지원한다. @Autowired에 대한 부분은 다음에 공부해보겠습니다.
Component Scan 적용해보기 기존의 AppConfig처럼 @Bean으로 등록하고 DI를 설정할 필요도 없이 끝났습니다. ㅎㅎ @ComponentSacn으로만 끝난거지만 만약 저와 같은 예제를 작성중이신 분들은 excludeFilters를 꼭 입력해주셔야하는데요. 그 이유는 우리가 이미 AppConfig라는 스프링 컨테이너를 하나 더 만들어놨기 때문에 동시에 등록이 되지 않도록 설정해주는 것입니다.
@Configuration
@ComponentScan(
//우리가 이미 등록해놓은 AppConfig를 등록하지 않도록
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Configuration.class)
)
public class AutoAppConfig { }
AppConfig와 같은 위치에 AutoAppConfig class를 만들고 다음과 같이 설정합니다.
Component 적용해보기우리가 빈으로 관리했던 class들에게 @Component를 붙여주면 @ComponentScan이 알아서 스프링 컨테이너에 모두 등록해줍니다! 그리고 여기서 컨테이너에 등록할때 빈 이름의 기본 전략이 있는데요 첫글자는 소문자로 변형한 뒤 모두 그래도 가게 됩니다. 위의 예시의 경우 MemberServiceImpl -> memberServiceImpl로 등록되어 집니다. 빈 이름을 직접 등록할 수도 있는데요 @Component("빈 이름")으로 등록해주면 @Bean으로 등록할때 이름을 변경했던것 처럼 사용하실 수 있습니다.
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Autowired public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
//테스트용
public MemberRepository getMemberRepository(){
return memberRepository;
}
}
컴포넌트 스캔 위치컴포넌트 스캔의 탐색 위치를 basePackages를 통해 지정할 수 있는 것인데요. 프로젝트 구조상 정말 필요하다면 사용하길 권장드립니다. basePackages의 default값은 @ComponentScan이 사용된 class의 package값을 default로 가지고 가기 때문에 일반적으로 또 spring boot에서 기본적으로 제공되는 프로젝트 구조가 프로젝트의 최상단으로 지정하시는걸 권장합니다.
@ComponentScan( basePackages = "hello.core", }
@Contorller, @Service, @Repository@SpringBootApplication@Service
여기까지 공부하시면서 프로젝트를 진행하고 계셨거나 회사에서 프로젝트를 진행하고 계신분들은 어? 우리 프로젝트는 @Component를 쓴적이 없고 @ComponentSacn도 안쓰는데 도대체 어떻게 스프링 컨테이너를 사용하고 있는거지? 우리 회사는 싱글톤으로 디자인되지 않고 객체를 무한히 생성하는건가??? 망했다 라고 생각하실 수 있는데요. 사실 그렇지 않습니다. Spring boot 프로젝트의 경우 최초 생선된 @SpringBootApplication 내부에 @ComponentScan이 들어있고 @Controller와 @Service, @Repository에는 @Component가 포함되어 있습니다.
Filter
@ComponentScan(
includeFilters = @Filter(
type = FilterType.ANNOTATION,
classes = IncludeComponent.class
),
excludeFilters = @Filter(
type = FilterType.ANNOTATION,
classes = ExcludeComponent.class
)
)
필터를 통해 컴포넌트의 스캔의 대상에 추가할수도 제외할수도 있는데요.
중복 등록과 충돌
만약 컴포넌트 스캔에 같은 이름의 빈을 중복으로 등록하게 되면 어떻게 될까요?