Spring ComponentScan과 Component

최준호·2021년 7월 6일
0

Spring

목록 보기
5/47

Component Sacn

  • 지금까지 빈을 등록하기 위해서 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

    • includeFilters
    • 컴포넌트 스캔 대상으로 추가
    • excludeFiltersincludeFilters는 @Component가 있으면 자동으로 스캔이 되니 사용할 일이 별로 없구요. excludeFilters의 경우 실무에서 가끔 사용된다고 하네요!
    • 컴포넌트 스캔 대상에서 제외
    • filter 사용법다음과 같이 filter에 type과 class를 지정해주시면 됩니다.
    @ComponentScan(
      includeFilters = @Filter(
        type = FilterType.ANNOTATION, 
        classes = IncludeComponent.class
      ),
    
      excludeFilters = @Filter(
        type = FilterType.ANNOTATION, 
        classes = ExcludeComponent.class
      ) 
    )
    • filter type 옵션
      • ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
      • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
      • ASPECTJ: AspectJ 패턴 사용
      • REGEX: 정규 표현식
      • CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리
  • 필터를 통해 컴포넌트의 스캔의 대상에 추가할수도 제외할수도 있는데요.

  • 중복 등록과 충돌

    1. 자동 빈 등록 + 자동 빈 등록
    2. 수동 빈 등록 + 자동 빈 등록2번의 경우 수동빈의 등록이 우선되며 자동 빈이 overriding됩니다. spring으로만 실행하게되면 실행이 되지만 최근 spring boot의 경우 이 경우도 에러로 처리합니다. 그 이유는 이렇게 되면 설정이 꼬이게 되어서 개발자가 잡기 어려운 버그를 만들어내기 때문입니다.
    3. 1번의 경우 ConflictingBeanDefinitionException 예외가 발생하게 되며 빈의 이름을 수정해야합니다.
  • 만약 컴포넌트 스캔에 같은 이름의 빈을 중복으로 등록하게 되면 어떻게 될까요?

출처 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

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글