본문 바로가기
Back-End/Spring

6.컴포넌트 스캔

by 두두리안 2021. 1. 7.
728x90

6.컴포넌트 스캔

  • 목차
    • 1.컴포넌트 스캔과 의존관계 자동주입 시작
    • 2.탐색위치와 기본 스캔대상
    • 3.필터
    • 4.중복 등록과 충돌

1.컴포넌트 스캔과 의존관계 자동주입 시작

  • 스프링 빈등록할때는 자바코드의 @Bean , xml 의 설정을 했다
  • 하지만 이렇게 등록해야되는 빈이 많다면 ? 귀찮고 누락되는 일도 많아진다
  • 스프링 설정정보가 없어도 자동으로 등록해주는 컴포넌트 스캔등장
  • Autowired 라는 의존관계도 자동으로 주입하는 기능도 필요하다

AutoAppConfig.java

@Configuration
@ComponentScan(
 excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class))
public class AutoAppConfig {

}
  • @ComponentScan 을 사용해서 컴포넌트 스캔을 이용
  • AutoAppConfig 는 @Bean 동록한게 없다
  • @Configuration 도 안에 @Component 가 있어서 자동으로 등록되기때문에 excludeFilters 을써서 지워준다
  • 타입 - ANNOTATION , classes - Configuration

MemoryMemberRepository

@Component
public class MemoryMemberRepository implements MemberRepository {}
  • MemoryMemberRepository 에 @Component 붙여준다

RateDiscountPolicy

@Component
public class RateDiscountPolicy implements DiscountPolicy {}
  • RateDiscountPolicy 에 @Component 붙여준다

MemberServiceImpl

@Component
public class MemberServiceImpl implements MemberService {

 private final MemberRepository memberRepository;

 @Autowired
 public MemberServiceImpl(MemberRepository memberRepository) {
 this.memberRepository = memberRepository;
 }
}
  • 기존 AppConfig 와 달리 의존관계를 직접 등록해야된다
  • 생성자에 @Autowired 붙여서 자동으로 주입하게 해준다

OrderServiceImpl

@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;
 }
}

AutoAppConfigTest

public class AutoAppConfigTest {

    @Test
    void basicScan(){
        AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext(AutoAppConfig.class);

        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberService.class);

    }

}
  • 아까만든 AutoAppConfig 를 스프링에 등록한다

image

  • 정상적으로 빈이 컴포넌트 스캔으로 자동으로 등록된것을 볼수 있다

2.탐색위치와 기본 스캔대상

  • 모든 자바클래스를 다 컴포넌트 스캔하면 시간이 오래걸린다
  • 필요한 위치부터 탐색하도록 시작위치를 지정할수 있다

AutoAppConfig

@Configuration
@ComponentScan(
        basePackages = "hello.Study_Spring.member",
        basePackageClasses = AutoAppConfig.class,
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Configuration.class)
)
public class AutoAppConfig {

}
  • basePackages 를 이용해서 컴포넌트 스캔을 지정할수 있다

image

  • basePackages 는 여러개를 지정할수 있다
  • basePackageClasses 를 이용해서 클래스도 지정할수 있다
  • basePackages , basePackageClasses 지정하지 않을 경우 hello.Study_Spring 의 하위 패키지부터 찾는다

참고

  • @SpringBootApplication 는 기본적으로 @ComponentScan 이 있다
  • 스프링부트를 쓰면 자동으로 컴포넌트를 스캔해서 빈이 등록된다

컴포넌트 스캔 기본대상

@Component
public @interface Controller {
}
@Component
public @interface Service {
}
@Component
public @interface Configuration {
}
  • @Component : 컴포넌트 스캔 사용
  • @Controller : 스프링 MVC 컨트롤러
  • @Service : 스프링 비즈니스 로직에서 사용
  • @Repository : 스프링 데이터 접근계층에서 사용 (데이터계층의 예외를 스프링 예외로 변환)
  • @Configuration : 스프링 설정 정보에서 사용 (스프링 빈이 싱글톤을 유지하도록 해줌)

3.필터

  • includeFilters : 컴포넌트 스캔 대상추가
  • excludeFilters : 컴포넌트 스캔에서 제외

컴포넌트 스캔대상에 추가할 어노테이션

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}

스캔대상에 추가할 클래스 및 제외할 클래스

@MyIncludeComponent
public class BeanA {
}

@MyExcludeComponent
public class BeanB {
}
  • BeanA : 추가
  • BeanB : 제외

스캔대상에 추가할 클래스 및 제외할 클래스

public class ComponentFilterAppConfigTest {

    @Test
    void filterScan(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
        BeanA beanA = ac.getBean("beanA", BeanA.class);
        assertThat(beanA).isNotNull();

        Assertions.assertThrows(NoSuchBeanDefinitionException.class,
                ()->ac.getBean("beanB",BeanB.class));

    }

    @Configuration
    @ComponentScan(
            includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = MyIncludeComponent.class),
            excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig{}
}

정리

  • @Component 충분
  • 스프링부트는 컴포넌트 스캔을 기본으로 제공하기 때문에 스프링 기본설정에 맞추어서 사용하자

4.중복 등록과 충돌

  • 자동빈 등록 vs 자동빈 등록
  • 수동빈 등록 vs 자동빈 등록

수동빈 등록 vs 자동빈 등록

  • 기존에는 수동빈이 우선권을 가진다 (오버라이딩)
  • 스프링 부트사용시 둘다 오류메시지를 날린다

참고

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard (스프링핵심기술)

728x90