Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/assembly-ownership/concept/concept-when-conditions-are-evaluated.md
T
DongHyeonkaandClaude Fable 5.1 b25357c48a docs(clean-architecture-backend-template): fold analysis into final and re-select one topic
- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다
- 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5
  (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를
  techviz 로 만들었다
- 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs
  돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다.
  Concept 이 인용한 코드가 SSOT 에 없어 뺐다
- candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 12:39:20 +09:00

115 lines
5.3 KiB
Markdown

---
kind: CONCEPT
slug: when-conditions-are-evaluated
title: 조건부 빈의 평가 시점 — 파싱 시점과 등록 시점
topic: assembly-ownership
project: clean-architecture-backend-template
status: 게시 전
sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
rootTreeNode: concept:when-conditions-are-evaluated
evidenceCapturedOn: 2026-09-01
assets:
- key: when-conditions-are-evaluated
file: ../../../final/evidence/rendered/when-conditions-are-evaluated.svg
evidence:
- ../../../final/evidence/raw/when-conditions-are-evaluated.txt
source:
- 원본 분석 절은 final/document.md#a05 §14.4 이다.
---
# 조건부 빈의 평가 시점 — 파싱 시점과 등록 시점
같은 `@ConditionalOnBean`이라도 그 클래스가 자동설정으로 등록되는지 `@Import`로 들어오는지에 따라 평가 시점이 다르다. 그 차이가 조건을 항상 거짓으로 만들 수 있다.
## 관계
- **ConditionalOnBean(DataSource)이 클래스 파싱 시점에 평가되어 여덟 빈이 사라졌다**
이 개념이 실제로 문제가 된 사례다.
- **ConditionalOnBean은 조건이 만족될 수 있는지까지 확인해야 한다**
이 개념에서 나온 확인 규칙이다.
- **ConditionalOnBean 사슬의 실제 평가 순서를 확인하지 않았다**
현재 리비전에 대한 미해결 질문이다.
## 본문
<!-- body:start -->
`@ConditionalOnBean`은 그 클래스가 **언제 평가되는가**에 따라 답이 달라진다. `@AutoConfiguration`으로 등록되면 다른 자동설정 이후에 평가되지만, plain `@Configuration`이 `@Import`로 들어오면 **클래스가 파싱되는 동안 — 대상 빈 정의가 존재하기 전에** 평가된다.
## 등록 방식이 평가 시점을 정한다
:::evidence key="when-conditions-are-evaluated" alt="분석 문서 final/document.md#a05 에서 이 기록의 근거 절을 그대로 잘라낸 16줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md#a05 발췌 — 16줄" zoom="true"
:::
## 이 저장소가 그 함정을 밟았다
여덟 빈이 조용히 사라졌다.
## 남은 회피 방법 둘
검증기를 주입받지 않고 직접 생성하기, 그리고 조건을 루트로 올리기.
:::note
현재 리비전의 각 조건부 빈이 어느 시점에 평가되는지는 ConditionEvaluationReport로 확인하지 않았다
:::
## 두 시점
`@ConditionalOnBean`은 "이 타입의 빈 정의가 이미 등록되어 있는가"를 묻는다. 그 질문의 답은 언제 묻느냐에 달라진다.
| 클래스가 들어오는 경로 | 조건이 평가되는 시점 |
|---|---|
| 자동설정 (`.imports`) | 자동설정 순서에 따라 등록 단계에서 |
| `@Import` | 그것을 import 하는 클래스가 파싱될 때 |
| 컴포넌트 스캔 | 스캔 단계에서 |
`@Import`로 들어오는 클래스가 문제다. 부모 설정이 파싱되는 시점에 자식 클래스의 클래스 수준 조건이 함께 평가되는데, 그 시점에는 자동설정이 만들 빈 정의가 아직 존재하지 않는다.
## 이 저장소가 겪은 형태
```java
/**
* <p>This class used to carry {@code @ConditionalOnBean(DataSource.class)}. It is imported by
* {@code PersistenceJpaRootAutoConfiguration} rather than auto-configured, so that condition was
* evaluated while the class was parsed — before the datasource bean definition existed — and was
* therefore false in every real deployment. All eight beans below silently disappeared, and nothing
* reported it because nothing depended on any of them. It surfaced only when the datasource
* validator was finally wired to a caller and the JPA Compose lane answered "No qualifying bean".
*/
```
두 문장이 이 개념의 핵심이다. 조건이 모든 실제 배포에서 거짓이었다는 것, 그리고 아무것도 그것을 보고하지 않았다는 것.
보고되지 않은 이유가 특히 중요하다. 사라진 여덟 빈에 의존하는 것이 없었기 때문이다. 의존이 있었다면 미충족 의존성으로 시끄럽게 실패했을 것이다.
## 해결 방향은 순서가 아니라 제거였다
```java
/**
* <p>The condition is removed rather than reordered: this class is reached only through the JPA
* root, which already carries the master switch, so "is there a datasource" has been answered yes
* by the time it is parsed. A bean here that needs one takes it as a parameter, and a missing
* datasource with the switch on is then a loud failure — which is the outcome that was wanted,
* rather than the layer vanishing.
*/
```
:::tip
조건을 옮기거나 순서를 바꾸는 대신, 그 조건이 이미 답해진 지점으로 도달 경로를 제한하고 조건 자체를 없앴다. 그리고 필요한 의존은 파라미터로 받게 해서, 없을 때 조용히 사라지는 대신 시끄럽게 실패하게 만들었다.
:::
## 확인 방법
정적으로는 두 가지를 본다.
1. 그 클래스가 `.imports`에 있는가, 아니면 다른 클래스가 `@Import` 하는가
2. 조건이 요구하는 빈을 누가 언제 등록하는가
런타임으로는 `debug=true` 부팅의 조건 평가 리포트가 답한다. `Negative matches` 항목의 사유 문자열이 "빈 정의 없음"인지 "타입 자체가 없음"인지를 구별해 준다.
<!-- body:end -->