여러 DataSource 빈 등록 우선순위를 가늠할 수 없었습니다
안녕하세요 토비님. 우선, 감동으로 청강을 이어갈 기회를 얻게되어 참 감사드립니다.
아래는 섹션8 - DataSource 자동 구성 클래스 파트의 @Bean 메서드 등록과정에 생긴 문제입니다.
의문점은 메서드 선언 순서에 영향을 받는다는것을 알게되서 다음처럼 2번의 테스트를 진행했습니다.
@Bean 메서드 선언순서 에 따른 등록 테스트
simple , hikari
hikari, simple
1 결과: simple 이 등록됨
/* DataSourceConfig.java */
@Bean
@ConditionalOnMissingBean
public DataSource simpleDriverDataSource() {
...
}
@Bean
@ConditionalOnMissingBean
@ConditionalMyOnClass("com.zaxxer.hikari.HikariDataSource")
public DataSource hikariDataSource() {
...
}
hikari 에 `@ConditionalMyOnClass` 가 있기때문에 등록될 것으로 예상했지만,
simple 이 등록되었습니다.
2 결과: hikari 가 등록됨
@Bean
@...
public DataSource hikariDataSource() {
...
}
@Bean
@...
public DataSource simpleDriverDataSource() {
...
}
기묘하게도 @Bean 메서드 선언순서를 바꾸니 Hikari 빈이 등록되었습니다. 이상하다 싶어, @Primary 와 @Order(n) 을 주고 다시 테스트 해봤지만, 영향을 주지 않았습니다.
질문: 위와 같이 @Bean 메서드 순서에 영향을 받는 이유가 궁금합니다.
이 결과로 @ConditionalOnClass 의 인식되는 FQCN 의 조건을 바꿔보기도 하고, 위치도 바꿔봤는데, 이렇다할 동작방식을 파악하기 힘들었습니다.
그리고 @Primay 나 @Order 를 붙여가며 추가적인 등록순서에 대해 테스트를 진행했으나, 이것들 역시 영향을 주지 않았습니다.
여러 곳에서 알아본 바, @Bean 메서드는 등록순서에 영향을 주지 않는것으로 알고있었는데, 이런 경우에는 어떤 매커니즘이 동작하는지가 궁금합니다. 이 결과를 보고 생각에 혼란이 와서 질문을 드리게 되었어요. 혹시 제가 놓친것이 있다면 조언을 부탁드려도 되겠습니까?
읽어주셔서 감사합니다☺️
답변 2
2
"@Bean 메서드는 등록순서에 영향을 주지 않는것으로 알고있었는데,"
등록 순서가 아니라 등록할 대상인지 판단하는 순서에 영향을 줍니다. 빈 오브젝트를 생성하는 순서를 결정하는 것은 또 다른 복잡한 결정 요인이 있습니다.
2
@ConditionalOnMissingBean이 붙은 경우 앞에서 같은 타입의 빈 정보가 이미 등록이 됐으면 빈 등록 조건을 통과하지 못하고 무시됩니다. 동일하게 DataSource 타입의 빈이 두 개가 나열되어있고 해당 조건이 붙어있으니 둘 중의 하나만 등록이 됩니다.
@ConditionalOnMissingBean은 @Conditional을 테스트하는 순서가 핵심입니다. 앞에서 먼저 동일 타입 빈이 등록됐으면 더 이상 빈 등록을 하지 말라는 것이니까요.
그렇다면 @Conditional이 붙은 클래스 또는 @Bean 메소드를 스프링이 가져와서 판단하는 순서는 어떻게 되는가가 중요한데요. 제가 테스트 해본 바로는 @Bean으로 같은 클래스에서 정의된 경우 소스 코드에 나열된 순서대로 하나씩 가져와서 조건을 테스트 합니다. 따라서 앞에 위치한 @Bean의 조건이 통과하는 경우 뒤의 것은 무시됩니다. 만약 앞에서 @ConditionalOnClass 같은 조건을 통과하지 못했다면 다음 @Bean도 가능성이 생기겠죠.
테스트 해보신 결과가 딱 이에 맞습니다.
@Primary, @Order 등은 "이미 빈으로 등록이 되는 것으로 결정된" 여러 빈들 사이에 의존 주입 우선순위나 오브젝트 생성 순위 등을 결정하는 것이므로 지금 질문하신 내용과는 아무 관련이 없습니다. 같은 타입의 @Bean 메소드 중에서 하나만 빈으로 등록되고 나머지는 빈 등록 대상에서 아예 빠지니까요.
그런데 실제로 스프링 부트에 DataSource를 등록하는 자동 구성 코드에서는 @Bean 메소드의 나열 순서로 하지 않고, 각 DataSource 빈을 가진 자동 구성 클래스를 따로 만들고 이를 @Import하도록 만들면서 @Import에 나열된 순서대로 조건을 판단하도록 만들었습니다.
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {이 경우에는 @Import안에 나열한 클래스 순서대로 조건을 테스트합니다. Hikari가 가장 앞에 있으니 일단 Hikari 클래스가 있는지 보고 그게 있으면 DataSource빈으로 등록될테고 나머지는 다 무시되겠죠. Hikari가 없는 경우는 그 다음 클래스로 조건 테스트가 넘어갈테고요.
이 정도로 이해하시면 문제 없을 듯합니다.
제가 강의 예제에서 스프링 부트처럼 DataSource 빈을 클래스로 다 분리해서 정의하고 @Import를 쓰는 대신 @Bean 메소드로만 구분해서 나열한 것은 예제가 너무 복잡해지지 않게 만들려고 했기 때문입니다.
2
저의 정리되지않은 우문에 디테일한 설명으로 혼란스런 생각정리에 도움이 많이 되었구요,
추가적인 Spring-boot 내부동작을 알려주셔서 이해에 도움이 많이 되었습니다.
감사드립니다😌
11강에서 cmd에서 spring shell에 $ init 하면 Fail 메세지
0
75
2
TestRestTemplate 을 통해 테스트 실행시 웹 요청 정보가 콘솔에 표시되지 않습니다.
0
83
1
섹션7. 자동구성 정보파일분리 강의 질문(@MyAutoConfiguration 붙힌 이유)
0
200
2
WebApplicationContext를 DispatcherServlet에 this로 넘기는 것
0
278
2
인프라 빈 구성 정보의 분리에서 EnableMyAutoConfiguration 질문드립니다.
0
209
2
질문드립니다.
0
232
2
spring boot 3.3.7로 학습중입니다.
0
369
2
Serverproperties 객체 생성 후 @Impor 어노테이션 사용 이유 용도
0
162
2
spring start io 에서 이제더이상 2.x버전은 지원하지 않는 것 같습니다.
1
295
2
Springboot 3.2 이상에서 파라미터 추론관련
0
913
4
binding error
0
220
3
Arrays.copyOf 메서드의 타입 세이프
1
155
2
MyOnClassCondition에 있는 matches method의 Invoke 횟수
1
231
3
인용구의 출처가 궁금합니다.
0
259
1
프로퍼티 빈의 후처리기 도입 AnnotationUtils의 사용
0
236
2
SimpleCacheConfiguration과 빈 등록
0
168
2
MyAutoConfigImportSelector 에서 생성자로 ClassLoader를 주입받을 수 있는 점
0
243
1
IntelliJ project jenerator spring initailizr
0
150
1
강의 자료 레퍼지토리에 업로드
0
215
1
강의자료
0
387
1
Hikari 라이브러리가 없으면 오류가 나는거 아닌가요
0
313
2
Tomcat 포트 프로퍼티 미설정시 랜덤 포트 설정 문의
0
471
5
@Import 로 Bean을 등록해야하는 기준이 뭔지 궁금합니다.
0
336
2
application.properties파일내 프로퍼티 이름
0
209
1





