@ComponentScan
- 자동으로
@Component
가 붙은 컴포넌트를 해당 빈 등록을 해준다. (싱글톤) - 빈 이름은 기본전략은
MemberServiceImpl class
->memberServiceImpl
로 앞의 글자만 소문자로 바꿔서 등록 해준다.- 이름을 수정 할 수 있음.
15:47:41.702 [Test worker] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@d049e53
15:47:41.708 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
15:47:41.758 [Test worker] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [SpringCorePrinciple_basic/core/build/classes/kotlin/main/com/inflearn/spring/core/discount/RateDiscountPolicy.class]
15:47:41.761 [Test worker] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [SpringCorePrinciple_basic/core/build/classes/kotlin/main/com/inflearn/spring/core/member/MemberServiceImpl.class]
15:47:41.762 [Test worker] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [SpringCorePrinciple_basic/core/build/classes/kotlin/main/com/inflearn/spring/core/member/MemoryMemberRepository.class]
15:47:41.763 [Test worker] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [SpringCorePrinciple_basic/core/build/classes/kotlin/main/com/inflearn/spring/core/order/OrderServiceImpl.class]
15:47:41.881 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
15:47:41.882 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
15:47:41.883 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
15:47:41.884 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
15:47:41.910 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'autoAppConfig'
15:47:41.913 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'rateDiscountPolicy'
15:47:42.033 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberServiceImpl'
15:47:42.042 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memoryMemberRepository'
15:47:42.044 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'memberServiceImpl' via constructor to bean named 'memoryMemberRepository'
15:47:42.045 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderServiceImpl'
15:47:42.047 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'memoryMemberRepository'
15:47:42.047 [Test worker] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'rateDiscountPolicy'
테스트 코드를 돌려보면, org.springframework.context.annotation.ClassPathBeanDefinitionScanner
이 동작해서 등록 해야 할
파일의 path를 찾는 것을 알 수 있다.
component scan의 base packages 지정은 굳이 하지 않고, 설정 클래스를 프로젝트 시작 위치에 두고, 쓰는게 좋다. (요즘 트렌드)
사실 이미, @SpringBootApplication
설정 안에 @ComponentScan
이 있다.
스캔 기본 대상
- @Component
- @Service
- 특별한 처리를 안함
- @Repository
- 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환 해준다.
- @Controller
- Spring MVC controller로 인식
- @Configuration
- 스프링 설정 정보로 인식, 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.
filter
FilterType option
- ANNOTATION
- 기본 값, 애노테이션을 인식하여 동작
- ASSIGNABLE
- 지정한 타입과 자식 타입을 인식해서 동작한다.
- ASPECTJ
- AspectJ 패턴 사용
- REGEX
- 정규 표현식
- CUSTOM
TypeFilter
인터페이스를 구현해서 처리
대세는 includeFilters
는 잘 안쓰고, ExcludeFilters
는 간혹 쓸 일이 있다. (실무에서 쓸 일이 좀 잦음)
중복 등록과 충돌
컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록 되는데, 그 이름이 같으면 스프링은 오류를 발생 시킨다.
ConflictBeanDefinitionException
이 발생함.
수동 등록 vs 자동 등록
두 등록 방식으로 같은 이름의 빈이 등록 되는 경우, 수동 등록한 빈이 우선권을 가지게 된다. 실제 실행 메시지에서는 overriding bean definition이란 메시지를
확인 할 수 있다.
Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing [Generic bean: class [com.inflearn.spring.core.member.MemoryMemberRepository]; scope=singleton;
그런데, 요즘 추세는 같은 이름으로 등록 되면, 수동/자동 모두 충돌나면 오류가 발생하도록 기본 값이 바뀌었다.
The bean 'memoryMemberRepository', defined in class path resource [com/inflearn/spring/core/AutoAppConfig.class], could not be registered. A bean with that name has already been defined in file [SpringCorePrinciple_basic/core/out/production/classes/com/inflearn/spring/core/member/MemoryMemberRepository.class] and overriding is disabled.
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
생성자 주입
- 수정자/필드 주입보다 생성자 주입을 쓰는게 권장 사항이다.
- 초기 생성시 의존성이 주입 되므로, 프로그램 시작-종료까지 고정 된다. (불변)
- 수정자 주입의 경우, public으로 열어둬야 하는데, 이는 중간에 변경 될 가능성도 충분히 있어 설계상 좋지 않다.
- 생성자 주입을 쓸때, 컴파일 오류로 버그를 빠르게 확인 할 수 있음.
- 필드에
final
을 사용하게 되면, 생성자에서 혹시라도 값이 설정 되지 않는 오류를 컴파일 시점에 막아준다.
Bean이 충돌 하는 경우
@Autowired
는 기본적으로 타입 기반으로 자동 등록을 해준다.
그런데, 타입은 같은데, 구현체가 다른 경우가 있다. 그럴때, 똑같이 빈 등록을 하게 되면 문제가 발생한다.
실제로 실행 해보면, NoUniqueBeanDefinitionException
에러가 발생하게 된다.
빈이 2개 이상일 때, 해결 방법
- @Autowired 필드명
- 생성자 주입의 경우, 파라미터 이름을 확인 한다. 하위 구현체의 이름으로 바꾸면 해결 가능하다.
- @Qualifier
- 추가 구분자를 붙여주는 방법이다. 빈 이름을 변경하는 것은 아니다.
- 만약, 이름을 넣어주고, 못찾으면
Qualifier
에 넣어준 이름으로 등록된 빈을 추가로 찾게 된다.
- @Primary
- 우선순위를 정하는 방법
@Primary vs @Qualifier
- 스프링은 자동보다 수동이 우선순위가 더 높다.
- 고로, @Primary보다 @Qualifier가 우선순위가 더 높게 된다.
자동 빈 등록 vs 수동 빈 등록
- 업무 로직 빈: 웹을 지원하는 컨트롤러, 핵심 비즈니스 로직, 데이터 계층
- 자동으로 빈 등록 해주는게 좋다.
- 기술 지원 빈: 기술적인 문제나 공통 관심사를 처리 할 때 주로 사용, 공통 로그처리, 데이터베이스 연결등 업무 로직을 위한 하부 기술 또는 공통 기술
- 수동으로 등록 해주는게 명확 하다.
반응형
'Spring > Spring 이야기' 카테고리의 다른 글
스프링 핵심 원리 기본편 강의 - Bean Definition (0) | 2024.03.26 |
---|---|
스프링 핵심 원리 기본편 강의 - Bean scope & Bean lifecycle (0) | 2024.03.26 |
스프링 핵심 원리 기본편 강의 - 스프링 (1) | 2024.03.26 |
스프링 핵심 원리 기본편 강의 - 싱글톤 (0) | 2024.03.26 |
스프링 핵심 원리 기본편 강의 - OOP와 스프링 (0) | 2024.03.26 |