# 주제: messaging-spring-boot-starter 가 실제로 만드는 빈 전수와, 만들지 않는 것 # revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 # ---- 진입점 ---- # src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports # dev.caskeleton.messaging.autoconfigure.MessagingPlatformRootAutoConfiguration # (한 줄. 나머지 설정은 전부 @Import 로 끌려온다.) # # MessagingPlatformRootAutoConfiguration # @ConditionalOnProperty(prefix="app.messaging", name="enabled", havingValue="true") # @Import({MessagingCoreAutoConfiguration, MessagingProviderSelection, # MessagingReliabilityAutoConfiguration, MessagingAdminAutoConfiguration}) # ---- 만드는 @Bean 전수 (38개) ---- # MessagingCoreAutoConfiguration (23) # messagingCredentialRequirementValidator, messagingPrefixMigrationValidator, # compiledMessagingConfiguration, messagingConfigurationKeyValidator, # validatedDestinationRegistry, destinationProfileValidator, messageSecurityValidator, # retryDecisionEngine, deadLetterOrchestrator, messagingRuntimeRegistry, # gracefulShutdownCoordinator, brokerSecurityStartupValidation, messagingShutdownLifecycle, # messagingRedactor, cardinalityGuard, blockingMessagePublisher, reactiveMessagePublisher, # batchMessagePublisher, credentialRuntimeRegistry(@ConditionalOnBean CredentialProvider), # brokerTlsPolicy, messagingEndpoint, messagingCodecs, messagingDestinationProfiles, # messagingDestinationAccess, messagingAdmission, messagingPublisher, messagingRuntimeInstallation # KafkaMessagingAutoConfiguration (7) # kafkaProfileValidator, kafkaProfileStartupValidation, kafkaTransactionProfileValidator, # kafkaPublishFailureClassifier, kafkaSecurityConfigurer(@ConditionalOnBean), # messagingKafkaProducer, messagingKafkaTransport # RabbitMessagingAutoConfiguration (4) — 단, 선택 불가 (아래) # rabbitProfileValidator, rabbitProfileStartupValidation, rabbitPublishFailureClassifier, # rabbitSecurityConfigurer(@ConditionalOnBean) # MessagingReliabilityAutoConfiguration (9) # outboxProperties, outboxRetryScheduler, outboxRelay(@ConditionalOnBean), # outboxRelayWorker(@ConditionalOnBean), outboxRelayLifecycle(@ConditionalOnBean), # outboxCleanupJob(@ConditionalOnBean), inboxRetentionPolicy, # inboxCleanupJob(@ConditionalOnBean), transactionalInboxHandler(@ConditionalOnBean) # MessagingAdminAutoConfiguration (4) # destructiveOperationGuard, adminOperationJournal, messagingAdminDurabilityValidator, # compositeTopologyValidator(@ConditionalOnBean) # ---- 만들지 않는 것 ---- # command: git grep -nE "ConsumerRegistrar|DeliveryProcessor|RetryExecutor|DeadLetterPublisher|MessagingConsumer|MessageListener|MessagingObservation|MessagingMetrics" -- src/messaging/messaging-spring-boot-starter/src/main # exit: 1 (출력 없음) # # => 스타터 전체에 컨슈머·배달 처리기·재시도 실행기·DLQ 발행기·관측 구현 빈이 하나도 없다. # 확정되는 것: # (a) 배포되는 컨텍스트는 발행할 수 있고 소비할 수 없다. # (b) MessagingObservation 빈이 없으므로 관측은 no-op 이다. # MessagingCoreAutoConfiguration:253 messagingRedactor, :264 cardinalityGuard 는 # MessagingMetrics 의 두 생성자 협력자인데, MessagingMetrics 자체를 만드는 곳이 없다. # messagingPublisher(:439-447)는 DefaultMessagePublisher 의 6-arg 생성자를 쓰고, # 그 체인은 NO_OBSERVATION 으로 끝난다(DefaultMessagePublisher.java:126-135). # (c) retryDecisionEngine(:167)·deadLetterOrchestrator(:179) 빈은 만들어지되 # 그 유일한 소비자(KafkaRetryExecutor, Kafka/RabbitDeadLetterPublisher)가 생성되지 않는다. # ---- 브로커 선택: rabbit 은 선택 불가 ---- # MessagingProviderSelection.java:63-68 # static final Map BROKERS_WITHOUT_A_TRANSPORT = # Map.of("rabbit", # "the Rabbit adapter ships its validators and security configuration but no " # + "MessagingTransport: its native channel publisher is not implemented, so a publish " # + "has nothing to travel on"); # selectedBroker(...):121-131 이 rabbit 을 IllegalStateException 으로 거절한다. # => 오늘 선택 가능한 브로커는 kafka 하나다. assemblableBrokerIds() == ["kafka"]. # RabbitMessagingAutoConfiguration 의 4개 빈은 도달 불가 경로에 있다. # ---- 프로바이더 설정 javadoc 자체 모순 ---- # KafkaMessagingAutoConfiguration.java:16-17 (첫 문단) # "Conditional on the Kafka client being present, so a service that depends on the starter for # RabbitMQ alone does not fail to start because a Kafka class is missing." # KafkaMessagingAutoConfiguration.java:26-29 (셋째 문단) # "Reached only when app.messaging.broker=kafka selected it. The @ConditionalOnClass this used to # carry could not select ..." # 클래스에 @ConditionalOnClass 가 없다(@Configuration(proxyBeanMethods=false) 뿐). # RabbitMessagingAutoConfiguration.java:15-16 / 22-23 도 같은 형태다. # => 같은 javadoc 안에서 첫 문단과 셋째 문단이 어긋난다. # ---- 선언된 의존 중 스타터가 import 하지 않는 것 ---- # command: git grep -n "import dev.caskeleton.messaging.cloudevents|import dev.caskeleton.messaging.claimcheck" -- src/messaging/messaging-spring-boot-starter # exit: 1 (출력 없음) # build.gradle 은 둘 다 implementation 으로 선언하고 modules.json 의 allowed_dependencies 에도 있다. # => messaging-cloudevents 와 messaging-claim-check 이 runtime_memberships:["app-bootstrap"] 을 # 갖는 이유가 이 선언이며, 스타터는 그 둘의 타입을 하나도 쓰지 않는다. # (두 리프의 외부 참조 0건은 각 리프 문서에 기록되어 있다.) # ---- 정리 잡은 빈이지만 스케줄되지 않는다 ---- # MessagingReliabilityAutoConfiguration.java:32-34 (클래스 javadoc) # "The cleanup jobs are beans but no scheduler is registered for them. Scheduling is the # application's decision: a service running several replicas usually wants one of them to run # cleanup, and auto-registering a fixed-rate task would have every replica delete the same rows." # => OutboxCleanupJob / InboxCleanupJob 의 runOnce 를 부르는 프로덕션 코드가 없다. # EVD-311 의 무제한 DELETE 는 애플리케이션이 이 잡을 스케줄하는 순간 발동한다. # (기본 배포에서는 아무것도 실행되지 않으므로, EVD-311 의 "프로덕션 기본 경로" 표현은 # "애플리케이션이 문서 지시대로 스케줄하면 발동하는 경로" 로 읽어야 정확하다.)