김영한님의 스프링 핵심 원리 - 기본편 강의
섹션6. 컴포넌트 스캔 강의 요약입니다.
컴포넌트 스캔과 의존관계 자동 주입
설정 정보가 없어도 자동으로 스프링 빈을 등록하는 @ComponentScan
@Component
가 붙은 클래스를 스캔에서 스프링 빈으로 등록한다.
의존 관계도 자동으로 주입하는 @Autowired
기능도 제공. 생성자에서 여러 의존관계를 한 번에 주입할 수 있다.
스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다. getBean(MemberRepository.class)
탐색 위치와 기본 스캔 대상
basePackages
, basicPackageClasses
사용하여 탐색 시작할 package 위치 지정 가능하다.
지정하지 않으면 @ComponentScan
이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
따로 지정하지 않고 설정 정보 클래스의 위치를 프로젝트 최상단에 두자. 스프링 부트도 이 방법을 기본으로 제공한다.
@Configuration
@ComponentScan(
basePackages = "hello.core.member", // 어디서부터 찾을지 시작위치 지정할 수 있음
basePackageClasses = AutoAppConfig.class, // 지정한 클래스의 package 위치를 탐색 시작함
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {
}
@SpringBootApplication
안에 ComponentScan이 들어있다. 스프링을 쓰면 따로 해줄 필요가 없다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
컴포넌트 스캔은 @Component
뿐만 아니라 밑의 Annotation들도 @Component
와 같은 역할을 하면서 추가 역할을 제공한다.
- @Controller: 스프링 MVC 컨트롤러로 인식
- @Repository: 스프링 데이터 접근 계층으로 인식. 데이터 계층의 예외를 스프링 예외로 변환
- @Configuration: 스프링 설정 정보로 인식. 스프링 빈이 싱글톤을 유지하도록 추가 처리를 한다.
- @Service: 스프링 비즈니스 로직에서 사용. 특별한 처리를 하지 않는다. 대신 개발자들이 핵심 비즈니스 로직이 여기에 있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.
중복 등록과 충돌
컴포넌트 스캔에서 같은 빈 이름을 등록했을 경우했을 경우 어떻게 될까?
- 자동 빈 등록 vs 자동 빈 등록 -> ConflictingBeanDenitionException 발생
- 수동 빈 등록 vs 자동 빈 등록
- 수동 빈이 우선권을 가짐
- 수동 빈이 자동 빈을 오버라이딩 해버린다.
자동 빈을 오버라이딩 한 log
23:47:57.103 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'memoryMemberRepository' with a different definition: replacing [Generic bean: class [hello.core.member.MemoryMemberRepository]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in file [C:\Users\chlgp\Github\Spring-Basic\core\out\production\classes\hello\core\member\MemoryMemberRepository.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=autoAppConfig; factoryMethodName=memberRepository; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in hello.core.AutoAppConfig]
BUT 현실은 개발자가 의도하기 보다는, 놓친 버그. 이렇게 되었을 경우 찾기 어려운 버그가 되어버려 최근 스프링부트는 오류가 발생하도록 기본 값을 바꾸었다. spring.main.allow-bean-definition-overriding=true
을 설정해두면 오버라이딩하여 Application이 실행되고, 기본 값으로 실행하면 오류가 발생하게 된다.
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'memoryMemberRepository', defined in class path resource [hello/core/AutoAppConfig.class], could not be registered. A bean with that name has already been defined in file [C:\Users\chlgp\Github\Spring-Basic\core\out\production\classes\hello\core\member\MemoryMemberRepository.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
Process finished with exit code 1
'Study > 인프런' 카테고리의 다른 글
[강의 수강] 스프링 핵심 원리 - 기본편 (2) (0) | 2023.03.19 |
---|---|
스프링(Spring) 의존관계 주입 방법 4가지 (0) | 2023.03.17 |
Spring @Configuration과 싱글톤 관계 (0) | 2023.02.05 |
스프링 개념 - 싱글톤 컨테이너란 (0) | 2023.02.05 |
BeanFactory와 ApplicationContext (0) | 2023.01.24 |