@ComponentScan
해당 어노테이션이 붙은 클래스의 하위 패키지를 모두 검사하여 @Component 가 붙은 클래스들을 스프링 빈으로 등록한다.
(% 검사 대상에는 우리가 @Controller, @Service, @Repoistory 같은 어노테이션들도 해당된다 )
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}//생성자 주입
}
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository ;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}// 생성자 주입
}
기존에는 MemberServiceImpl, OrderServiceImpl클래스에서 MemberRepository의 어떤 구현체에 의존할지를 판단하기 위해 AppConfig 파일로 가서 다음과 같이 의존성을 주입했다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
System.out.println("call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
System.out.println("AppConfig.orderService");
return new OrderServiceImpl(memberRepository(),discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
System.out.println("AppConfig.memberRepository");
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy(){
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
하지만이렇게 등록해야 할 스프링 빈이 수십, 수백개가 되면 일일이 등록하기도
귀찮고, 설정 정보도 커지고, 누락하는 문제도 발생한다 그래서 사용하는것이 ComponentScan 어노테이션이다.
말그대로 @Component를 Scan 해주는 기능인데 @Component붙어있는 클래스들을 자동적으로
Spring Bean에 등록해준다.
@Configuration
@ComponentScan()
public class AutoAppConfig {
}
@Component
public class MemberServiceImpl implements MemberService{
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}//생성자 주입
}
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository ;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}// 생성자 주입
}
@Autowired를 사용한 이유는 의존성 주입을 받기 위함인데 "타입" 기반으로 자동으로 의존관계를 주입해준다.
사용할 구현체에도 @Component를 달아준다.
@Component
public class RateDiscountPolicy implements DiscountPolicy {
private int discountPercent = 10; // 10% 할인
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP){
return price * discountPercent / 100;
}else{
return 0;
}
}
}
@Component
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
나는 spring boot를 사용하여 개발을 했을땐 분명 @ComponentScan을 사용한적이 없었다.
그 이유는 @ComponentScan이 해당 어노테이션이 붙은 클래스의 하위부를 모두 검사해주기 때문인데 Springboot의 메인 어플리케이션에는
@SpringBootApplication
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
위와 같이 @SpringBootApplication이 달려있다. 안으로 들어가보면
사진과 같이 @ComponentScan 어노테이션을 포함하고 있었다.
메인 어플리케이션은 항상 프로젝트 최상단에 있었으니 @ComponentScan을 사용할 필요가 없었던것이다.
이렇게 멋모르고 사용했던 Spring boot의 장점을 하나 알아간다..