-
Spring - 컴포넌트 스캔(Component Scan)Spring/Spring 2022. 1. 23. 21:47728x90반응형
컴포넌트 스캔(Component Scan)
- 스프링 빈을 등록할 때 @Bean 어노테이션을 이용하여 설정 정보에 직접 등록할 스프링 빈을 나열했다.
- 등록해야 할 스프링 빈이 많을 경우에는 설정 정보도 커지고 누락하는 문제가 발생한다.
- 이러한 문제를 해결하기 위해 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록해주는 컴포넌트 스캔이라는 기능을 제공한다.
- 의존 관계도 자동으로 주입하는 @Autowired라는 기능도 제공한다.
컴포넌트 스캔을 하게 되면 AppConfig에서 해주었던 빈 등록을 하지 않아도 된다. 대신 @Component 어노테이션이 붙은 클래스를 스캔하여 스프링 빈으로 등록하게 된다.
컴포넌트 스캔은 해당 패키지부터 하위 패키지까지 스캔해준다.
@Configuration @ComponentScan public class AutoAppConfig { }
이제 스프링 컨테이너에 빈 등록할 클래스(AppConfig에서 수동 등록했던 빈)에 @Conponent 어노테이션을 붙여준다.
@Component public class MemoryMemberRepository implements MemberRepository {} @Component public class RateDiscountPolicy implements DiscountPolicy {} @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; } }
AppConfig에서 수동으로 빈 등록을 할 때에는 의존 관계도 직접 명시했었다. @Conponent에서는 의존 관계는 @Autowired를 이용해 의존 관계 주입을 해준다.
여기서 알아야 할 점은 수동으로 빈 등록과 의존 관계를 설정했을 때와는 달리
컴포넌트 스캔을 이용하게 되면 구현체를 변경할 시 @Component를 A -> B로 변경해야
하는 점으로 '수정'이 일어나는 트레이드 오프가 발생하게 된다.
이 경우는 OCP를 위반하였지만 컴포넌트 스캔의 한계로 편리성을 위해 사용하는
트레이드 오프로 이해하면 된다.
컴포넌트 스캔의 관례
- 컴포넌트 스캔은 해당 위치부터 하위 패키지를 모두 스캔해준다.
- 컴포넌트 스캔을 시작하는 패키지 위치를 지정해줄 수 있지만 일반적으로
메인 설정 정보 클래스의 위치를 프로젝트 최상단에 둔다. - 메인 설정 정보 클래스는 프로젝트를 대표하는 정보이기 때문에 프로젝트 최상단에 둔다.
- 참고로 스프링 부트의 대표 시작 정보인 @SpringBootApplication를
프로젝트 시작 루트 위치에 두는 것이 관례이다.
컴포넌트 스캔의 기본 대상
해당 어노테이션들의 소스 코드를 보면 @Component를 포함하고 있는 것을 알 수 있다.
- @Component : 컴포넌트 스캔에서 사용
- @Controller : 스프링 MVC 컨트롤러에 사용,
스프링 MVC 컨트롤러로 인식 - @Service : 스프링 비즈니스 로직에서 사용
- @Repository : 스프링 데이터 접근 계층에서 사용
스프링 데이터 접근 계층으로 인식, 데이터 계층의 예외를 스프링 예외로 변환해준다. - @Configuration : 스프링 설정 정보에서 사용
스프링 설정 정보로 인식, 스프링 빈이 싱글톤으로 유지하도록 추가 처리
컴포넌트 스캔의 필터
- includeFilters : 컴포넌트 스캔 대상을 추가로 지정
- excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정
필터의 예시를 들기 위해 사용자 정의 어노테이션을 만들어보자
package hello.core.scan.filter; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyComponent { } @MyIncludeComponent public class BeanA { }
이제 설정 정보 클래스에서 필터를 적요해 보자
@ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), // excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) public class ComponentFilterAppConfig { }
includeFilters를 이용하면 스캔 범위에 없는 해당 클래스(BeanA)를 컴포넌트 스캔을 할 수 있다. 반대로 excludeFilters를 이용하면 스캔 범위에 있는 해당 클래스(BeanA)를 컴포넌트 스캔을 하지 않도록 제외할 수 있다.
위 필터는 거의 사용할 일이 없으니 사용법만 알아두도록 하자.
빈의 중복 등록과 충돌
- 같은 빈 이름으로 @Component를 이용하여 2번 등록
자동 빈 등록으로 같은 이름의 빈을 2번 등록할 시
- ConflictingBeanDefinitionException 예외 발생 - 같은 빈 이름으로 @Component와 @Bean을 이용하여 2번 등록
자동 1번, 수동 1번으로 같은 이름의 빈을 2번 등록할 시
- 수동으로 등록 한 빈이 우선권을 가진다(수동 빈이 자동 빈을 오버라이딩 해버린다.)
- 하지만 이와 같은 경우는 잡기 어려운 버그가 만들어지므로 스프링 부트에서는 오류를 발생시키도록 변경됨
// 자동 등록 @Component public class MemoryMemberRepository implements MemberRepository {} @Configuration @ComponentScan public class AutoAppConfig { // 수동 등록 @Bean(name = "memoryMemberRepository") public MemberRepository memberRepository() { return new MemoryMemberRepository(); } }
728x90반응형'Spring > Spring' 카테고리의 다른 글
Spring - 동일 타입의 빈이 2개 이상일 경우 의존관계 주입 방법 (0) 2022.01.24 Spring - 다양한 의존관계 주입 방법(생성자 주입, 수정자 주입, 필드 주입) (0) 2022.01.24 Spring - 싱글톤 컨테이너 (0) 2022.01.23 Spring - 스프링 컨테이너(Spring Container)와 종류, 그리고 Bean 조회 방법 (0) 2022.01.18 스프링의 등장 - 순수 자바 코드에서 스프링까지 3 , IoC(제어의 역전)와 Di 그리고 등장하는 스프링 (0) 2022.01.16