AR삽질러

Spring 컴포넌트스캔 (12) 본문

JAVA/Spring

Spring 컴포넌트스캔 (12)

아랑팡팡 2023. 8. 11. 20:27
728x90

Component Scen

 - ComponentScan은 spring이 클래스의 경로를 스캔하여 Spring Bean으로 등록할 클래스를 찾는 기능이다.

컴포넌트 스캔을 사용하면 수동으로 각각의 빈을 등록하지 않아도 특정 애노테이션을 가진 클래스를 자동으로 빈으로 등록하고 관리할 수 있다.

 

주요 애노테이션

@Component 가장 기본적인 컴포넌드 애노테이션으로 빈을 등록할 클래스에 사용된다.

@Controller MVC컨트롤러로 사용되는 클래스에 사용한다.
@Service 서비스 로직을 담당하는 클래스에 사용한다.
@Repository 데이터 저장소에 접근하는 클래스 DAO(Data Access Object)에 사용한다.

 

컴포넌트 스캔을 사용하려먼 @ComponentScan을 설정정보에 붙여 사용한다. 여기서 @ComponentScant은 해당 클래스의 패키지부터 하위 패키지까지 모두 스캔하게된다.

@ComponentScan은 @Component가 붙은 모든 클래스를 스프링 빈으로 등록한다.

생성자에 @Autowired를 지정하게 되면 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아 주입하게된다.

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

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

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

}

@ComponentScan탐색시작위치

 - basePackage, basePackageClasses 두가지 속성으로 시작위치를 지정할 수 있다.

 - 시작위치를 지정하지 않았을때 @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작위치가 된다.

 

2. ComponentScan의 기본대상 애노테이션

@Component 기본 컴포넌트 애노테이션으로 클래스를 스프링 빈으로 등록한다.
@Controller 주로 웹 MVC의 컨트롤러로 사용되며 내부적으로 @Component를 포함하고 있어 스프링 빈으로 자동 등록된다.
@Service 비즈니스 로직을 담당하는 서비스 레이어의 컴포넌트에 주로 사용된다.
@Repository @데이터 저장소에 접근하는 DAO(Data Access Object)혹은 Repository레이어 컴포넌트에 사용된다.
@Configuration 스프링 설정정보를 담고 있는 클래스에서 사용되며 @Bean과 함께 사용되어 스프링 컨테이너에 빈 객체를 등록한다.

 

3. Filter

 필터를 통해서 원하는 타입의 컴포넌트만 스캔하거나 특정 컴포넌트를 제외하는 필터링 기능을 사용할 수 있다.

 

1) includeFilters

 -  스캔 대상 중에서 특정 조건에 맞는 컴포넌트만 스캔 대상으로 포함하고자 할때 사용한다.

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

 

2) excludeFilters

 - 스캔 대상 중에서 특정 조건에 맞는 컴포넌트를 스캔 대상에서 제외하고자 할때 사용한다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
@MyIncludeComponent
public class BeanA {
}
@MyExcludeComponent
public class BeanB {
}
public class ComponentFilterAppConfigTest {
    @Test
    void filterScan() {
        ApplicationContext 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 = @Filter(type = FilterType.ANNOTATION, classes =
                    MyIncludeComponent.class),
            excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
                    MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig {
    }
}

MyIncludeComponent : BeanA : 컴포넌트 스캔대상에 포함

MyExcludeComponent : BeanB : 컴포넌트 스캔대상에서 제외

 

includeFilters : @MyIncludeCompoent 애노테이션이 붙은 컴포넌트만 스캔 대상에 포함한다고 지정

excludeFilters : @MyExcludeCompoent 애노테이션이 붙은 컴포넌트만 스캔 대상에 제외한다고 지정

 

ComponentFilterAppConfigTest Class

 - filterScan() 테스트 메서드를 이용해 spring container에서 BeanA는 존재하고 BeanB는 존재하지 않다는것을 검증한다.

 

FilterType Option

ANNOTAION 지정된 애노테이션 타입에 의해 지정된 컴포넌트를 포함하거나 제외한다. org.example.SomeAnnotaion
ASSIGNABLE_TYPE 지정된 타입 또는 그 하위 타입의 컴포넌트를 포함하거나 제외한다. org.example.SomeClass
ASPECTJ AspectJ패턴 표현식을 사용하여 컴포넌트를 포함하거나 제외한다. org.example..*Service+
REGEX 정규 표현식을 사용하여 컴포넌트를 포함하거나 제외한다. org.example\/Default.*
CUSTOM 사용자 지정 TypeFilter 구현을 사용하여 컴포넌트를 포함하거나 제외한다. org.example.MyTypeFilter

 

결론 : @Component으로 충분하기 때문에 includeFilters를 사용할 일은 없지만 excludeFilters는 간혹 사용할 일이 있다.

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

 

4. 중복 등록과 충돌

1) 자동 빈 등록 vs 수동 빈 등록

 - 스프링 컨테이너는 @Component를 사용하여 빈을 자동으로 등록하지만 @Bean 애노테이션을 사용하여 Java설정파일에서 수동으로 빈을 등록할 수 도 있다.

 

2) 자동 빈 등록 vs 자동 빈 등록

 - 컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되지만 등록된 빈의 이름이 같은 경우 스프링 요류가 발생한다.

* ConflictingBeanDefinitionException 예외 발생

해결방법 

 - 빈이름 변경

 - 수동 빈 등록

 - 특정 패키지 제외

 - 명시적인 충돌 해결

 

3) 수동 빈 등록 vs 자동 빈 등록

 

 

 

728x90
반응형
LIST