ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • spring[5] ComponentScan과 Component
    개인 공부/spring 2021. 5. 16. 08:48
    728x90
    반응형

    Component Sacn

    • 지금까지 빈을 등록하기 위해서 AppConfig class에 사용자가 일일히 @Bean으로 관리해주어야 했습니다. 하지만 이건 개발자에게 너무 귀찮은 작업이고 누락하게 되면 큰 장애가 발생하게됩니다. 그래서 Spring은 @Bean으로 일일히 등록하지 않아도 자동으로 스프링 빈으로 등록해주는 @ComponentScan과 @Component annotation을 제공합니다.
    • 컴포넌트 스캔을 사용하게 되면 DI가 애매해집니다. 지금까진 수동으로 의존관계를 주입했지만 Bean이 자동으로 등록되게되니 의존관계를 설정할 수 있는 부분이 사라진것입니다. 그래서 @Autowired annotation을 지원한다. @Autowired에 대한 부분은 다음에 공부해보겠습니다.
    • Component Scan 적용해보기
        @Configuration
        @ComponentScan(
                //우리가 이미 등록해놓은 AppConfig를 등록하지 않도록
                excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
        )
        public class AutoAppConfig {
        }
      기존의 AppConfig처럼 @Bean으로 등록하고 DI를 설정할 필요도 없이 끝났습니다. ㅎㅎ @ComponentSacn으로만 끝난거지만 만약 저와 같은 예제를 작성중이신 분들은 excludeFilters를 꼭 입력해주셔야하는데요. 그 이유는 우리가 이미 AppConfig라는 스프링 컨테이너를 하나 더 만들어놨기 때문에 동시에 등록이 되지 않도록 설정해주는 것입니다.
    • 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

    728x90
    반응형
Designed by Juno.