@ComponentScan
@ComponentScan은 @Component 및 @Service, @Repository, @Controller, @Configuration등과 같이 @Component가 붙어있는 Class들을 자동으로 Scan하여 스프링 Bean으로 등록해주는 역할을 수행한.
@Component는 클래스에 사용되며, 빈으로 등록될 때에는 클래스명을 사용하여 등록한다.
이때, 클래스의 맨 앞글자만 소문자로 바꿔서 저장한다.
만약 Member 클래스의 경우에는 Bean으로 등록되는 경우 member로 등록되는 것이다.
컴포넌트 스캔과 자동 의존관계 주입이 어떻게 동작하는지 그림으로 알아보자.
1. @ComponentScan

2. Autowired 의존관계 자동 주입

생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.
이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.
@ComponentScan의 탐색 위치
기본 값으로는 @ComponenetScan이 사용된 패키지를 시작 위치로 하여, 해당 패키지와 하위 디렉토리를 모두 탐색한다.
만약 탐색의 기준이 되는 패키지를 직접 지정해주고 싶다면 basePackages 옵션을 사용할 수 있다.
@ComponentScan( basePackages = "hello.core" }
이러면 hello.core 패키지를 포함해서 하위에 있는 모든 패키지를 탐색한다.
또한 basePackageClasses 속성을 통해 클래스를 지정하면, 지정한 클래스의 패키지를 탐색 시작 위치로 지정할 수 있다.
필터
includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다
컴포넌트 스캔 대상에 추가할 애너테이션
package filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
컴포넌트 스캔 대상에서 제외할 애너테이션
package filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
@MyIncludeComponent
public class BeanA {
}
// 컴포넌트 스캔 대상에서 포함시킬 클래스
@MyExcludeComponent
public class BeanB {
}
// 컴포넌트 스캔 대상에서 제외할 클래스
설정 정보와 전체 테스트 코드
package filter;
import org.junit.jupiter.api.Assertions;
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.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.assertThat;
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 = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
static class ComponentFilterAppConfig {
}
}

FilterType 옵션
- ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
- ASPECTJ: AspectJ 패턴 사용
- REGEX: 정규 표현식
- CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리
중복 등록과 충돌
빈 이름이 중복되는 경우에는 두가지 상황이 있다.
1. 자동 빈 등록 vs 자동 빈 등록
2. 수동 빈 등록 vs 자동 빈 등록
자동 빈 등록 vs 자동 빈 등록
컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
ConflictingBeanDefinitionException 예외 발생
수동 빈 등록 vs 자동 빈 등록
수동 빈 등록이 우선권을 가진다. (수동 빈이 자동 빈을 오버라이딩 해버린다.)
수동 빈 등록시 남는 로그
Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing
최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값을 바꾸었다.
수동 빈 등록, 자동 빈 등록 오류시 스프링 부트 에러
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
'🍀Spring > 기본' 카테고리의 다른 글
[Spring] 빈 생명주기 콜백 (0) | 2024.08.09 |
---|---|
[Spring] 의존관계 자동 주입 (0) | 2024.08.09 |
[Spring] 싱글톤 컨테이너 (0) | 2024.07.28 |
[Spring] 스프링 컨테이너와 스프링 빈 (0) | 2024.07.20 |
[Spring] 예제 만들기 - 객체 지향 원리 적용 (0) | 2024.07.19 |
@ComponentScan
@ComponentScan은 @Component 및 @Service, @Repository, @Controller, @Configuration등과 같이 @Component가 붙어있는 Class들을 자동으로 Scan하여 스프링 Bean으로 등록해주는 역할을 수행한.
@Component는 클래스에 사용되며, 빈으로 등록될 때에는 클래스명을 사용하여 등록한다.
이때, 클래스의 맨 앞글자만 소문자로 바꿔서 저장한다.
만약 Member 클래스의 경우에는 Bean으로 등록되는 경우 member로 등록되는 것이다.
컴포넌트 스캔과 자동 의존관계 주입이 어떻게 동작하는지 그림으로 알아보자.
1. @ComponentScan

2. Autowired 의존관계 자동 주입

생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.
이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.
@ComponentScan의 탐색 위치
기본 값으로는 @ComponenetScan이 사용된 패키지를 시작 위치로 하여, 해당 패키지와 하위 디렉토리를 모두 탐색한다.
만약 탐색의 기준이 되는 패키지를 직접 지정해주고 싶다면 basePackages 옵션을 사용할 수 있다.
@ComponentScan( basePackages = "hello.core" }
이러면 hello.core 패키지를 포함해서 하위에 있는 모든 패키지를 탐색한다.
또한 basePackageClasses 속성을 통해 클래스를 지정하면, 지정한 클래스의 패키지를 탐색 시작 위치로 지정할 수 있다.
필터
includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다
컴포넌트 스캔 대상에 추가할 애너테이션
package filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
컴포넌트 스캔 대상에서 제외할 애너테이션
package filter;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
@MyIncludeComponent
public class BeanA {
}
// 컴포넌트 스캔 대상에서 포함시킬 클래스
@MyExcludeComponent
public class BeanB {
}
// 컴포넌트 스캔 대상에서 제외할 클래스
설정 정보와 전체 테스트 코드
package filter;
import org.junit.jupiter.api.Assertions;
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.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.assertj.core.api.Assertions.assertThat;
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 = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
MyIncludeComponent.class),
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
MyExcludeComponent.class)
)
static class ComponentFilterAppConfig {
}
}

FilterType 옵션
- ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.
- ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.
- ASPECTJ: AspectJ 패턴 사용
- REGEX: 정규 표현식
- CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리
중복 등록과 충돌
빈 이름이 중복되는 경우에는 두가지 상황이 있다.
1. 자동 빈 등록 vs 자동 빈 등록
2. 수동 빈 등록 vs 자동 빈 등록
자동 빈 등록 vs 자동 빈 등록
컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
ConflictingBeanDefinitionException 예외 발생
수동 빈 등록 vs 자동 빈 등록
수동 빈 등록이 우선권을 가진다. (수동 빈이 자동 빈을 오버라이딩 해버린다.)
수동 빈 등록시 남는 로그
Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing
최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값을 바꾸었다.
수동 빈 등록, 자동 빈 등록 오류시 스프링 부트 에러
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
'🍀Spring > 기본' 카테고리의 다른 글
[Spring] 빈 생명주기 콜백 (0) | 2024.08.09 |
---|---|
[Spring] 의존관계 자동 주입 (0) | 2024.08.09 |
[Spring] 싱글톤 컨테이너 (0) | 2024.07.28 |
[Spring] 스프링 컨테이너와 스프링 빈 (0) | 2024.07.20 |
[Spring] 예제 만들기 - 객체 지향 원리 적용 (0) | 2024.07.19 |