목차
- 컴포넌트 스캔 - 컴포넌트 스캔과 의존관계 자동 주입 시작하기
- 컴포넌트 스캔 - 탐색 위치와 기본 스캔 대상
- 컴포넌트 스캔 - 필터
- 컴포넌트 스캔 - 중복 등록과 충돌
필터
- includeFilters : 컴포넌트 스캔 대상을 추가로 지정.
- excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정 (나름 사용됨)
두가지를 사용한 예제를 만들어 보자.
scan하위에 filter패키지를 생성한다.
먼저, annotation처럼 사용할 인터페이스들을 생성한다.
MyExcludeComponent(인터페이스)
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {//이것이 붙은 것은 컴포넌트 스캔에서 제외한다
}
MyIncludeComponent (인터페이스)
package hello.core.scan.filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {//이것이 붙은 것은 컴포넌트 스캔에 추가한다.
}
이제 생성한 annotation을 적용한 클래스를 생성한다.
ComponentFilterAppConfigTest
package hello.core.scan.filter;
import hello.core.AppConfig;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ComponentFilterAppConfigTest {
@Test
void filterScan(){
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class); // include하여 컴포넌트 스캔대상에 포함되어 빈으로 등록되어야 정상
assertThat(beanA).isNotNull();
// ac.getBean("beanB", BeanB.class); //exclude하여 컴포넌트 스캔대상에서 제외되어 등록되지 않아야 정상 -> 에러
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{
}
}
이제 둘을 테스트 해볼 클래스를 생성한다.
@ComponentScan을 이용하여, 제외시킬 것과 포함시킬 것을 다음과 같이 작성해준다.
FilterType은 5가지 옵션이 있다.
- ANNOTATION: default, 애노테이션을 인식해서 동작한다(생략가능)
- ex) org.example.SomeAnnotation
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
- ex) org.example.SomeClass
- ASPECTJ: AspectJ 패턴 사용
- ex) org.example..*Service+
- REGEX: 정규 표현식
- ex) org\.example\.Default.*
- CUSTOM: TypeFilter 이라는 인터페이스를 직접 구현해서 처리
- ex) org.example.MyTypeFilter
중복 등록과 충돌
컴포넌트 스캔에서 같은 빈 이름을 등록하는 경우는
- 자동빈등록vs자동빈등록
- @Component("자유이름") 이거를 똑같이 지은경우 -> 거의 발생 x
- 수동빈등록vs자동빈등록
자동 빈 등록 vs 자동 빈 등록
컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
ConflictingBeanDefinitionException 예외 발생
수동 빈 등록 vs 자동 빈등록
이러한 오류를 발생시키기 위해, 우리가 만든 AutoAppConfig에
이미 우리가 자동으로 등록시킨 memoryMemberRepository라는 이름을 가진 수동 빈 을 생성한다.
@Component 자동으로 등록된 memoryMemberRepository
@Component
public class MemoryMemberRepository implements MemberRepository {}
수동으로 등록한 memoryMemberRepository
@Configuration
@ComponentScan(
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes =
Configuration.class)
)
public class AutoAppConfig {
@Bean(name = "memoryMemberRepository")
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
오류가 발생하지 않는다.
수동빈 등록이 우선권을 가지고, 수동 빈이 자동빈을 오버라이딩 한다.
스프링에서 친절하게 로그를 남겨준다.
Overriding bean definition for bean 'memoryMemberRepository' with a different
definition: replacing
하지만, 이런 경우는 에러가 나지 않기 때문에 의도하지 않은 잡기 어려운 버그가 만들어진다.
따라서 현재는 스프링부트가 수동빈과 자동빈 등록이 충돌이 나면 오류를 발생시키게 기본값을 바꿨으며,
(즉 오버라이딩으로 처리되지 않음)
스프링부트 CoreApplicaiton을 실행해 보면, 오류가 발생한다.
만약, 오버라이딩을 해주도록 설정을 바꾸고 싶으면,
applicaiton.properties에
spring.main.allow-bean-definition-overriding=true
이를 추가해 주면된다.
현재 default로 false이기 때문에 에러가 발생함
'Backend > Spring' 카테고리의 다른 글
[Spring] 의존관계 자동 주입 2) 조회 빈이 2개 이상 (0) | 2021.10.06 |
---|---|
[Spring] 의존관계 자동 주입 1) 의존 주입 방법 (0) | 2021.10.06 |
[Spring] 컴포넌트 스캔 1) 컴포넌트 스캔과 의존관계 주입 (0) | 2021.09.30 |
[Spring] 싱글톤 컨테이너 3) @Configuration (0) | 2021.09.30 |
[Spring] 싱글톤 컨테이너 2) 싱글톤 방식의 주의점 (0) | 2021.09.30 |