일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 스프링
- Javascript
- 생성자 주입
- sqld
- 스프링 빈
- resultMap
- mybatis
- 스프링 부트 기본
- 스프링 부트
- thymeleaf
- 싱글톤
- 스프링부트
- @Configuration
- spring
- springboot
- SQL
- Effective Java
- JPA
- jdbc
- assertThat
- 스프링 프레임워크
- java
- assertThrows
- db
- 스프링 부트 입문
- 필드 주입
- DI
- DIP
- kafka
- 스프링 컨테이너
- Today
- Total
선 조치 후 분석
[Spring] Spring Framework - 핵심 원리 (31) - 빈 중복 등록+ 빈 충돌 + 자동 빈 등록 vs 자동 빈 등록 + 수동 빈 등록 vs 자동 빈 등록 + ConflictingBeanDefinitionException 본문
[Spring] Spring Framework - 핵심 원리 (31) - 빈 중복 등록+ 빈 충돌 + 자동 빈 등록 vs 자동 빈 등록 + 수동 빈 등록 vs 자동 빈 등록 + ConflictingBeanDefinitionException
JB1104 2022. 2. 23. 21:14빈 중복 등록+ 빈 충돌 + 자동 빈 등록 vs 자동 빈 등록 + 수동 빈 등록 vs 자동 빈 등록 + ConflictingBeanDefinitionException
컴포넌트 스캔에서 같은 빈 이름을 등록하면 어떻게 될까?
다음 두 가지 상황이 있다.
1. 자동 빈 등록 vs 자동 빈 등록
2. 수동 빈 등록 vs 자동 빈 등록
자동 빈 등록 vs 자동 빈 등록
컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.
-> ConflictingBeanDefinitionException 예외 발생
코드로 알아보자.
1. OrderServiceImpl의 @Component명 변경
@Component("service")
public class OrderServiceImpl implements OrderService
2. MemberServiceImpl의 @Component명 변경
@Component("service")
public class MemberServiceImpl implements MemberService
3. AutoAppConfigTest로 테스트 실행
결과는 아래처럼 친절하게(?) ConflictingBeanDefinitionException 예외를 발생시켜서 원인을 말해준다.
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [hello.core.AutoAppConfig]; nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:
Annotation-specified bean name 'service' for bean class [hello.core.order.OrderServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [hello.core.member.MemberServiceImpl]
수동 빈 등록 vs 자동 빈 등록
만약 수동 빈 등록과 자동 빈 등록에서 빈 이름이 충돌되면 어떻게 될까?
1. MemoryMemberRepository와 똑같은 Bean을 수동으로 등록
@Bean(name = "memoryMemberRepository")
MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
2. AutoAppConfig 테스트
결과를 확인하면 Overriding bean definition로 시작하는 내용이 나온다. 그리고 테스트도 통과한다.
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;
initMethodName=null; destroyMethodName=null; defined in file [D:\EZEN08\MySpring Framework\core\bin\main\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; initMethodName=null; destroyMethodName=(inferred); defined in hello.core.AutoAppConfig]
이 경우, 수동 빈 등록이 우선권을 가진다! (수동 빈이 자동 빈을 오버 라이딩해버린다.)
참고 (중요)
개발자가 의도적으로 설정해서 이런 결과가 만들어지기보다는 여러 설정들이 꼬여서 이런 결가가 만들어지는 경우가
대부분이다! 그러면 정말 잡기 어려운 버그가 만들어진다. 그래서 최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌 나면 오류가 발생하도록 기본 값을 바꾸었다.(즉, 기본값이 False!!!)
CoreApplication을 실행하면 아래처럼 오류가 발생한다.
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 [D:\EZEN08\MySpring Framework\core\bin\main\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
만약에 오버 라이딩하고 싶으면 application.properties에 콘솔에서 가르치고 있는 내용인
spring.main.allow-bean-definition-overriding=true을 등록하면 스프링 부트로 실행해도 오류가 발생하지 않는다.
spring.main.allow-bean-definition-overriding=true
2022-02-23 21:06:48.903 INFO 14268 --- [ main] hello.core.CoreApplication : Starting CoreApplication using Java 15.0.2 on DESKTOP-6G8OBCG with PID 14268 (D:\EZEN08\MySpring Framework\core\bin\main started by bock1 in D:\EZEN08\MySpring Framework\core)
2022-02-23 21:06:48.907 INFO 14268 --- [ main] hello.core.CoreApplication : No active profile set, falling back to default profiles: default
call AppConfig.memberRepository
call AppConfig.memberService
call AppConfig.orderService
2022-02-23 21:06:50.142 INFO 14268 --- [ main] hello.core.CoreApplication : Started CoreApplication in 2.111 seconds (JVM running for 3.049)