사용자 정의 스타터
Board 관측 라이브러리를 핵심·자동 구성·스타터로 분리하고 자동 구성 메타데이터, 선택적 클래스 경로, 구성 속성, 사용자 빈 우선 규칙, 바이너리 호환성을 사용자 관점에서 완성합니다.
자체 스타터의 목표는 의존성 몇 개를 모으는 데 그치지 않습니다. 사용자가 스타터 하나와 속성만 추가해 안전한 기본값을 얻고, 자신의 빈으로 교체하며, 선택적 통합이 없을 때 클래스 로딩 실패 없이 시작해야 합니다. 핵심 API, 자동 구성, 의존성 집계 모듈을 분리하면 각 책임과 버전 호환성이 보입니다.
핵심 모듈 공개 규칙
관찰 이벤트와 수집 대상 인터페이스, 마스킹 정책처럼 라이브러리 본질은 프레임워크 애노테이션 없이 표현할 수 있습니다. 자동 구성 모듈이 이 API의 기본값 구현과 Spring 연결을 제공합니다. 사용자는 내부 구성 클래스가 아니라 핵심 규칙을 주입받습니다.
package board.observe;
import java.time.Instant;
public interface BoardObservationSink {
void record(Event event);
record Event(
String operation,
String outcome,
long elapsedNanos,
Instant occurredAt
) {
public Event {
if (operation.isBlank() || outcome.isBlank() || elapsedNanos < 0) {
throw new IllegalArgumentException("invalid observation event");
}
}
}
}핵심이 SLF4J나 Micrometer 타입을 공개 시그니처에 노출하면 사용자에게 적용되는 버전 제약이 커집니다. 실제 통합을 별도 선택적 모듈로 제공할지 결정합니다.
자동 구성 모듈
속성이 활성화되고 사용자 수집 대상이 없을 때 콘솔 또는 레지스트리 수집 대상을 만듭니다. 선택적 Micrometer 클래스를 중첩 구성으로 격리합니다. 구성 속성 레코드는 사용자가 IDE 메타데이터와 검증을 받을 수 있는 공개 설정 API입니다.
package board.observe.autoconfigure;
import java.time.Clock;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import board.observe.BoardObservationSink;
@AutoConfiguration
@ConditionalOnProperty(
prefix = "board.observation",
name = "enabled",
havingValue = "true",
matchIfMissing = true)
public class BoardObserveAutoConfiguration {
@Bean
@ConditionalOnMissingBean
Clock observationClock() {
return Clock.systemUTC();
}
@Bean
@ConditionalOnMissingBean(BoardObservationSink.class)
BoardObservationSink observationSink() {
return event -> System.out.printf(
"operation=%s outcome=%s%n",
event.operation(), event.outcome());
}
}기본값 활성화가 안전한지 검토합니다.
외부 네트워크로 전송하는 수집 대상이라면 matchIfMissing=false가 더 적합합니다.
콘솔 기본값은 페이로드 마스킹과 출력량 제한을 갖습니다.
스타터 모듈
스타터 산출물은 핵심과 자동 구성 모듈을 가져오고 컴파일 코드가 거의 없을 수 있습니다. 선택적 외부 연동은 기본으로 끌어오지 않고 별도 스타터로 나눕니다. 사용자가 웹 애플리케이션이 아니어도 핵심 관찰을 사용할 수 있게 웹 스타터에 강제 결합하지 않습니다.
자동 구성 JAR 파일의 AutoConfiguration.imports 메타데이터에 구성 클래스를 등록하고 빌드 과정에서 해당 항목을 읽을 수 있는지 확인합니다.
스타터 JAR 파일이 아니라 자동 구성 JAR 파일에 메타데이터를 두면 직접 의존성을 추가한 사용자에게도 일관되게 동작합니다.
구성 처리기로 속성 메타데이터를 생성하되 처리기는 런타임 산출물에 포함하지 않습니다. 배포된 POM과 Gradle 모듈 메타데이터가 선택적 의존성 의미를 제대로 전달하는지 확인합니다.
사용자 재정의·비활성화
기본값, 비활성화 속성, 사용자 시계, 사용자 수집 대상, 선택적 클래스 부재, 유효하지 않은 속성을 각각 작은 컨텍스트에서 실행합니다. 빈 개수뿐 아니라 동일성과 실패 메시지를 확인합니다.
default -> Clock 1, Sink 1
enabled=false -> Sink 0
custom Sink -> custom 1, default 0
optional registry missing -> core Sink still starts
invalid configuration -> startup failure with property path전체 예제 애플리케이션은 배포된 산출물을 리포지토리에서 받아 컴파일·패키지합니다. 다중 프로젝트 소스 의존성만 쓰면 배포 메타데이터 오류를 놓칩니다.
공개 호환성 정책
핵심 인터페이스 메서드 추가는 사용자 구현을 깨뜨릴 수 있습니다. 기본 메서드 추가, 새 하위 인터페이스 도입, 주 버전 상향 가운데 적합한 방법을 선택합니다. 속성 이름 변경은 사용 중단 예정 메타데이터와 마이그레이션 기간을 제공합니다.
자동 구성 내부 빈 이름과 조건 배치는 공개 규칙으로 약속하지 않습니다. 사용자가 재정의하는 타입, 속성 키, 기본값 동작, 필수 Java·Boot 버전을 문서화합니다.
Boot 주 버전별로 별도 스타터가 필요한지 호환성 행렬을 유지합니다. 무리한 리플렉션으로 여러 비호환 API를 한 바이너리에서 지원하면 테스트 표면이 커집니다.
공급망·배포 산출물 검증
소스·Javadoc, 라이선스, SBOM, 시그니처, 체크섬을 발행하고 의존성 혼동 공격을 막는 그룹 소유권을 사용합니다.
릴리스 후보를 빈 사용자 프로젝트에 설치해 AutoConfiguration.imports 메타데이터, 속성 메타데이터, 네이티브/AOT 구동 여부를 확인합니다.
스타터가 사용자 로깅 공급자나 서버를 강제로 바꾸지 않게 그래프를 검토합니다. 의존성 개수와 JAR 크기가 릴리스마다 급증하면 선택적 통합이 핵심 모듈에 스며들었는지 봅니다.
운영 진단 정보
정보 엔드포인트나 시작 로그에 낮은 카디널리티 라이브러리 버전과 활성화 여부를 기록할 수 있습니다. 속성 전체와 비밀 정보는 노출하지 않습니다. 수집 대상 실패가 핵심 요청을 막는지 실패 허용 정책을 명시합니다.
연습 문제
Board 관측 스타터의 세 모듈 Gradle 그래프, 공개 패키지, AutoConfiguration.imports 메타데이터, 활성화 기본값, 선택적 Prometheus 통합, 사용자 재정의, 배포 검증 절차를 설계하세요.
해설 보기
사용자가 사용자 정의 수집 대상만 구현해도 자동 구성의 나머지 시계 기본값은 사용할 수 있어야 합니다.
구성 클래스 전체를 @ConditionalOnMissingBean 하나로 막지 않고 빈마다 사용자 정의를 우선하는 규칙을 둡니다.
package board.observe;
public record ObservationDefaults(
boolean enabled,
boolean failOpen,
int maximumOperationLength
) {
public ObservationDefaults {
if (maximumOperationLength < 8 || maximumOperationLength > 128) {
throw new IllegalArgumentException("unsafe operation length");
}
}
}외부 전송 수집기는 제한된 대기열과 실패 메트릭을 별도 통합 모듈에서 제공합니다.