basePackages
: 탐색할 패키지의 시작 위치를 지정한다. 이 패키지를 포함해서 하위 패키지를 모두 탐색@Configuration
@ComponentScan(
// 스프링 빈 등록시 제외할 것을 등록
// @Configuration이 붙은 것은 제외
excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class),
// hello.core.member 패키지와 하위패키지까지
basePackages = "hello.core.member"
)
public class AutoAppConfig {
}
basePackageClasses
: 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다@Configuration
@ComponentScan(
// 스프링 빈 등록시 제외할 것을 등록
// @Configuration이 붙은 것은 제외
excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class),
// AutoAppConfig가 위치한 패키지와 하위 패키지까지
basePackageClasses = AutoAppConfig.class
)
public class AutoAppConfig {
}
@ComponentScan
이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다com.hello
com.hello.serivce
com.hello.repository
이렇게 있을 경우com.hello
프로젝트 시작 루트에 AppConfig
같은 메인 설정 정보를 두고, @ComponentScan
애노테이 션을 붙이고, basePackages
지정은 생략한다.@Component
: 컴포넌트 스캔에서 사용 @Controller
: 스프링 MVC 컨트롤러에서 사용@Service
: 스프링 비즈니스 로직에서 사용 @Repository
: 스프링 데이터 접근 계층에서 사용 @Configuration
: 스프링 설정 정보에서 사용@Component
포함하고있음@Component
public @interface Controller { }
@Component
public @interface Service { }
@Component
public @interface Configuration { }
includeFilters
: 컴포넌트 스캔 대상을 추가로 지정한다excludeFilters
: 컴포넌트 스캔에서 제외할 대상을 지정한다package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
package hello.core.scan.filter;
@MyIncludeComponent
public class BeanA {
}
package hello.core.scan.filter;
@MyExcludeComponent
public class BeanB {
}
-Test
public class ComponentFilterAppConfigTest {
@Test
void filterScan() {
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
// includeFilters 에 `MyIncludeComponent` 애노테이션을 추가해서 BeanA가 스프링 빈에 등록된다
Assertions.assertThat(beanA).isNotNull();
// excludeFilters 에 `MyExcludeComponent` 애노테이션을 추가해서 BeanB는 스프링 빈에 등록되지 않는다
org.junit.jupiter.api.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 {
}
}
org.example.SomeAnnotation
org.example.SomeClass
org.example..*Service+
org\.example\.Default.*
TypeFilter
이라는 인터페이스를 구현해서 처리org.example.MyTypeFilter
excludeFilters
를 사용하기는 하지만 스프링의 기본 설정에 최대한 맞추어 사용하는 것을 권장하고, 선호하는 편임ConflictingBeanDefinitionException
예외 발생Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing
@Component
public class MemoryMemberRepository implements MemberRepository {}
@Configuration
@ComponentScan(
excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
@Bean(name = "memoryMemberRepository")
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true