준비
이전에 작성된 글인 싱글톤(Singleton)의 코드가 있어야 본 글의 코드 예제를 수행할 수 있습니다.
컴포넌트 스캔(Component Scan)이란?
지금까지 스프링 빈을 등록할 때 @Bean을 사용하였습니다.
이는 관리할 빈이 많아진다면 관리하기 버거운 사태가 생기게 됩니다.
스프링은 굳이 빈 설정파일을 만들지 않거나, @Bean을 쓰지 않고도 빈을 등록하는 컴포넌트 스캔(Component Scan)이라는 기능을 제공합니다.
- @ComponentScan을 사용하여 @Component가 붙은 모든 클래스를 스프링 빈으로 등록할 수 있습니다.
- 의존관계도 자동으로 주입하는 @Autowired 기능도 제공합니다.
sample_Project 패키지에 AutoDependencyConfig.java 클래스를 생성합니다.
package developingman.sample_Project;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AutoDependencyConfig {
}
- 기존의 DependencyConfig 소스 코드와 비교한다면 @Bean으로 등록한 클래스를 볼 수 없습니다.
- 주의 >> ComponentScan을 사용하면 @Configuration이 붙은 설정 정보도 자동으로 등록됩니다.
- @Configuration이 붙은 설정 정보가 자동으로 등록되는 이유는 @Configuration 코드에 @Component annotation이 있기 때문입니다.
- 기존에 작성한 AppConfig가 있다면 정상적인 작동이 되지 않습니다.
- DependencyConfig 등 @Configuration 설정이 된 파일이 있을 시 아래의 코드를 추가합니다 :
@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class)) - XML 방식의 component scan
<beans>
<context:component-scan base-package="com.acme"/>
</beans>
예제 코드
기존에 작성된 코드를 아래의 코드 예제에 맞춰 수정합니다.
memberService.java 클래스 수정
package developingman.sample_Project.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
public void createMember(Member member){
memberRepository.postMember(member);
}
public Member getMember(Long memberId){
return memberRepository.getMember(memberId);
}
public void deleteMember(Long memberId){
memberRepository.deleteMember(memberId);
}
}
SnackService.java 클래스 수정
package developingman.sample_Project.snack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SnackService {
private static SnackRepository snackRepository;
@Autowired
public SnackService(SnackRepository snackRepository){
this.snackRepository = snackRepository;
}
public void createSnack(Snack snack){
snackRepository.postSnack(snack);
}
public Snack editSnack(Long snackId, String korName, int price){
return snackRepository.patchSnack(snackId, korName, price);
}
public Snack getSnack(Long snackId){
return snackRepository.getSnack(snackId);
}
public void deleteSnack(Long snackId){
snackRepository.deleteSnack(snackId);
}
}
MemberRepository.java 클래스 수정
package developingman.sample_Project.member;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class MemberRepository {
private static Map<Long, Member> members = new HashMap<>();
public void postMember(Member member) {
members.put(member.getMemberId(), member);
}
public Member getMember(Long memberId) {
return members.get(memberId);
}
public void deleteMember(Long memberId){
members.remove(memberId);
}
}
SnackRepository.java 클래스 수정
package developingman.sample_Project.snack;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class SnackRepository {
private static Map<Long, Snack> snacks = new HashMap<>();
public void postSnack(Snack snack){
snacks.put(snack.getSnackId(),snack);
}
public Snack patchSnack(Long snackId, String korName, int price){
Snack snack = snacks.get(snackId);
snack.setKorName(korName);
snack.setPrice(price);
return snacks.put(snackId, snack);
}
public Snack getSnack(Long snackId){
return snacks.get(snackId);
}
public void deleteSnack(Long snackId){
snacks.remove(snackId);
}
}
기존에 코드에서 @Component와 @Autowired를 추가하였습니다.
- @ComponentScan: @ComponentScan이 등록된 곳에서 @Component를 가져오기 위해 사용됩니다.
- @Autowired: 생성자 의존성 주입에 필요한 설정 정보 대신 의존관계 자동 주입을 해줍니다.
BasePackages
BasePackages는 탐색할 패키지의 시작 위치를 지정하고, 해당 패키지부터 하위 패키지 모두 탐색합니다.
- @ComponentScan()의 매개변수로 basePackages = ""를 줄 수 있습니다.
- 지정하지 않으면, @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 됩니다.
- 설정 정보 클래스의 위치를 프로젝트 최상단에 두고 패키지 위치는 지정하지 않은 방법이 가장 편할 수 있습니다.
- 스프링 부트를 사용하면 @SpringBootApplication을 이 프로젝트 시작 루트 위치에 두는 것을 추천합니다.
- @SpringBootApplication에 @ComponentScan이 들어있습니다.
컴포넌트 스캔 기본 대상
- @Component: 컴포넌트 스캔에서 사용됩니다.
- @Controller & @RestController: 스프링 MVC 및 REST 전용 컨트롤러에서 사용됩니다.
- @Service: 스프링 비즈니스 로직에서 사용됩니다.
- @Repository: 스프링 데이터 접근 계층에서 사용됩니다.
- 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해 줍니다.
- @Configuration: 스프링 설정 정보에서 사용됩니다.
- 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 합니다.
- 해당 클래스의 소스 코드에는 @Component를 포함하고 있습니다.
필터
- includeFilters: 컴포넌트 스캔 대상을 추가로 지정합니다.
- excludeFilters: 컴포넌트 스캔에서 제외할 대상을 지정합니다.
- FilterType 옵션
- ANNOTATION: 에너테이션으로 인식해서 동작합니다.
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작합니다.
- ASPECTJ: AspectJ 패턴을 사용합니다.
- REGEX: 정규 표현식을 나타냅니다.
- CUSTOM: TypeFilter라는 인터페이스를 구현해서 처리합니다.
'Spring' 카테고리의 다른 글
[Spring] DI(Dependency Injection) 종합 실습 (0) | 2023.04.10 |
---|---|
[Spring] 다양한 의존 관계 주입 방법 (0) | 2023.04.09 |
[Spring] 싱글톤(Singleton) (0) | 2023.04.06 |
[Spring] 빈 스코프(Bean Scope) (0) | 2023.04.05 |
[Spring] 빈(Bean) (0) | 2023.04.04 |