fix: 하네스 제거 및 keycloak 문서 보강
This commit is contained in:
@@ -1 +0,0 @@
|
||||
../../vault/20-evidence/official-docs/adapter-java-spi-serviceloader.md
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: Java SPI (Service Provider Interface) + ServiceLoader — adapter 대안
|
||||
source_type: official-doc
|
||||
url: https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
|
||||
archive_url:
|
||||
status: raw
|
||||
confidence: high
|
||||
related_branches: [feature-integration-adapter-templates, feature-skeleton-package-blueprint-contract]
|
||||
related_projects: [ca-tmpl]
|
||||
tags: [ca-tmpl, adapter, java, spi, serviceloader, plugin, alternative]
|
||||
created: 2026-05-22
|
||||
last_reviewed: 2026-05-27
|
||||
---
|
||||
|
||||
# Java SPI (Service Provider Interface) + ServiceLoader — adapter 대안
|
||||
|
||||
> Layer: `raw/official-docs/` — Oracle Java Tutorial "Creating Extensible Applications" 의 SPI/ServiceLoader 발췌. ca-tmpl `feature-integration-adapter-templates` branch의 **adapter on/off 메커니즘 대안 4** (Java 표준 plugin architecture) 근거.
|
||||
|
||||
## Parent / 활용 branch (필수)
|
||||
|
||||
| Branch | 이 자료가 정당화하는 결정 |
|
||||
|---|---|
|
||||
| [[raw/branch-notes/feature-integration-adapter-templates]] | Group G-I 대안 4 (Java SPI / ServiceLoader plugin architecture) 의 시맨틱·한계 — Spring `@ConditionalOnProperty` 채택 결정의 비교 기준 |
|
||||
| [[raw/branch-notes/feature-skeleton-package-blueprint-contract]] | adapter 후보 package 설계 시 "Spring DI vs classpath SPI" 분기 검토 근거 |
|
||||
|
||||
## 컨텍스트 / 왜 저장했는지
|
||||
|
||||
ca-tmpl `feature-integration-adapter-templates` branch의 **대안 4**. branch는 Spring `@ConditionalOnProperty` 기반 optional module을 채택했음. 대안으로 Java 표준 SPI (ServiceLoader)가 있는데, 둘의 시맨틱 차이를 명확히 보존.
|
||||
|
||||
## 출처 / Source
|
||||
|
||||
- 원본 URL: https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
|
||||
- 보조 URL: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ServiceLoader.html
|
||||
- 아카이브 URL: (미수집)
|
||||
- 저자 / 조직: Oracle (Java Tutorial 공식)
|
||||
- 발행 상태: Java SE 표준 (JDK 1.6+), 현재까지 유효
|
||||
- 마지막 확인일: 2026-05-27
|
||||
|
||||
## 핵심 인용 / Key quotes (verbatim)
|
||||
|
||||
> [§Service Provider Interface (SPI) 정의] "The set of public interfaces and abstract classes that a service defines. The SPI defines the classes and methods available to your application."
|
||||
|
||||
> [§ServiceLoader 역할] "The `java.util.ServiceLoader` class helps you find, load, and use service providers. It searches for service providers on your application's class path or in your runtime environment's extensions directory. It loads them and enables your application to use the provider's APIs."
|
||||
|
||||
> [§META-INF/services 등록] "To register your service provider, you create a provider configuration file, which is stored in the `META-INF/services` directory of the service provider's JAR file. The name of the configuration file is the fully qualified class name of the service provider, in which each component of the name is separated by a period (`.`), and nested classes are separated by a dollar sign (`$`)."
|
||||
|
||||
> [§Lazy instantiation + caching] "Providers are located and instantiated on demand. A service loader maintains a cache of the providers that were loaded. Each invocation of the loader's `iterator` method returns an iterator that first yields all of the elements of the cache, in instantiation order. The service loader then locates and instantiates any new providers, adding each one to the cache in turn. You can clear the provider cache with the `reload` method."
|
||||
|
||||
> [§Default constructor 요구] "The `ServiceLoader` class requires that the single exposed provider type has a default constructor, which requires no arguments. This enables the `ServiceLoader` class to easily instantiate the service providers that it finds."
|
||||
|
||||
## Claims Extracted / 추출된 주장
|
||||
|
||||
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
||||
|---|---|---|---|---|---|
|
||||
| SPI-C1 | SPI 는 service 가 정의하는 public interfaces + abstract classes 집합으로, application 이 사용할 수 있는 classes/methods 를 정의 | [§Service Provider Interface (SPI) 정의] "The set of public interfaces and abstract classes that a service defines. The SPI defines the classes and methods available to your application." | `official-vendor-doc` | Java SE SPI 패턴 일반 | SPI 가 on/off 토글 메커니즘을 포함한다는 뜻은 아님 — provider 등록 = 자동 활성 |
|
||||
| SPI-C2 | `ServiceLoader` 는 application classpath 또는 runtime extensions directory 에서 service provider 를 검색·로드하여 application 에 노출 | [§ServiceLoader 역할] "It searches for service providers on your application's class path or in your runtime environment's extensions directory. It loads them and enables your application to use the provider's APIs." | `official-vendor-doc` | classpath 기반 plugin discovery 시나리오 | property/env 기반 활성 제어 메커니즘이 있다는 뜻은 아님 (classpath 존재 = 활성) |
|
||||
| SPI-C3 | provider 등록은 JAR 의 `META-INF/services/` 디렉토리에 fully qualified service interface name 의 파일을 두고, 각 줄에 provider FQN 을 나열하는 방식 | [§META-INF/services 등록] "To register your service provider, you create a provider configuration file, which is stored in the `META-INF/services` directory of the service provider's JAR file. The name of the configuration file is the fully qualified class name of the service provider" | `official-vendor-doc` | JAR-packaged provider 배포 | YAML/property 기반 등록이나 Spring `application.yml` 통합이 가능하다는 뜻은 아님 |
|
||||
| SPI-C4 | provider 는 on-demand instantiate 되며 `ServiceLoader` 는 캐시를 유지, `iterator()` 호출 시 캐시된 provider 부터 instantiation order 로 yield, `reload()` 로 캐시 비우기 가능 | [§Lazy instantiation + caching] "Providers are located and instantiated on demand. A service loader maintains a cache of the providers that were loaded. Each invocation of the loader's `iterator` method returns an iterator that first yields all of the elements of the cache, in instantiation order... You can clear the provider cache with the `reload` method." | `official-vendor-doc` | 단일 `ServiceLoader` 인스턴스의 라이프사이클 | "lazy" 가 모든 provider 의 instantiate 비용을 0 으로 만든다는 뜻은 아님 — 첫 iterate 시 등록된 모든 provider 가 검출됨 |
|
||||
| SPI-C5 | `ServiceLoader` 는 exposed provider type 에 **default (no-arg) constructor 요구** | [§Default constructor 요구] "The `ServiceLoader` class requires that the single exposed provider type has a default constructor, which requires no arguments." | `official-vendor-doc` | 표준 `ServiceLoader.load()` 경로 | constructor injection 으로 dependency 주입이 가능하다는 뜻은 아님 (Java 9+ `provider()` static method 패턴은 별도 문서) |
|
||||
|
||||
## Usage Boundaries / 적용 경계
|
||||
|
||||
- **이 자료가 직접 증명하는 것**:
|
||||
- `SPI-C1`: SPI 의 정의 (interface + abstract class 집합)
|
||||
- `SPI-C2`: `ServiceLoader` 의 검색 경로 (classpath / extensions dir)
|
||||
- `SPI-C3`: `META-INF/services/<FQN>` 파일 형식 의무
|
||||
- `SPI-C4`: lazy instantiation + 캐시 + `reload()` 시맨틱
|
||||
- `SPI-C5`: provider 의 default constructor 강제 요구
|
||||
- **이 자료가 증명하지 않는 것**:
|
||||
- SPI 가 property/env 기반 on/off 제어를 지원한다는 명제 (classpath 존재 = 활성, 본 인용 범위에서 disable 메커니즘 부재)
|
||||
- Spring DI 컨테이너와의 통합 (Spring `@Autowired`/`@Transactional` 이 SPI provider 에 적용된다는 보장 없음)
|
||||
- JPMS (Java 9+) `provides ... with ...` 선언과의 정확한 통합 시맨틱 (별도 JPMS 문서 필요)
|
||||
- 검출 시점이 Spring `ApplicationContext` 시작 시점과 어떻게 정렬되는지
|
||||
- **내 프로젝트(ca-tmpl) 에 적용하려면 추가 확인이 필요한 것**:
|
||||
- `ConditionalOnProperty` 처럼 "기본 disabled + property 로 enable" 시맨틱을 SPI 로 표현하려면 별도 wrapper layer 가 필요 (본 문서로 보장 안 됨)
|
||||
- branch 의 "Layer 1 ApplicationContext bean count = 0" 검증을 SPI provider 에 적용할 수 없음 — SPI provider 는 Spring bean 이 아니므로 별도 검증 메커니즘 필요
|
||||
|
||||
## 메모 / Notes (내 프로젝트 해석 — 미검증)
|
||||
|
||||
> 본 섹션은 자료 직접 인용 아님. ca-tmpl 결정 컨텍스트 해석.
|
||||
|
||||
- 적용 시나리오: 프레임워크 / 라이브러리 작성자 입장에서 사용자가 외부 jar drop-in으로 기능 확장하게 하고 싶을 때 (JDBC Driver, SLF4J binding, JPA provider, Spring Boot `SpringApplicationRunListener` 등 실제로 사용 중).
|
||||
- 장점:
|
||||
- **표준 JDK**: 의존성 없음. ClassLoader 수준 작동.
|
||||
- **classpath drop-in**: jar만 넣으면 `META-INF/services/` 자동 감지.
|
||||
- JPMS (Java 9+) `provides ... with ...` 선언과 통합.
|
||||
- 단점 / ca-tmpl 적용 시 한계:
|
||||
- **on/off 제어가 없음**: classpath에 존재하면 즉시 provider로 등록. branch가 요구한 "disabled state 기본값"을 표현할 표준 메커니즘이 없음. property 기반 게이팅이 SPI에는 없음.
|
||||
- **DI 통합 없음**: ServiceLoader가 instantiate하는 객체는 Spring bean이 아님. `@Autowired`, `@Transactional` 등 Spring 기능 미적용. wrapping이 별도로 필요.
|
||||
- **default constructor 강제**: 의존 주입을 생성자로 받을 수 없음.
|
||||
- **검출 비용**: provider 검색이 lazy하지만 한 번 트리거되면 모든 provider iterate.
|
||||
- **branch Layer 1 검증 (ApplicationContext bean count = 0) 불가능**: bean이 애초에 ApplicationContext에 없음. 검증 메커니즘을 별도로 짜야 함.
|
||||
- ca-tmpl 결정과의 차이:
|
||||
- ca-tmpl: Spring DI + `@ConditionalOnProperty` 1차. ApplicationContext bean 등록 여부로 enable/disable 검증.
|
||||
- SPI: classpath 기반 자동 발견. enable/disable이 jar inclusion/exclusion으로만 표현됨 (= build artifact 분리). branch의 "build artifact 1개 + env 주입" 결정과 충돌.
|
||||
- 채택 시점 후보: 프레임워크 자체를 만들 때, 또는 third-party가 plugin을 작성하게 해야 할 때. application 내부 adapter on/off에는 부적합.
|
||||
- 신뢰도: `official-doc` 등급. Oracle Java Tutorial + JDK API doc.
|
||||
|
||||
## Related / 관련
|
||||
|
||||
- 같은 주제 다른 official-doc:
|
||||
- [[raw/official-docs/adapter-spring-boot-autoconfig-custom-starter]] (ca-tmpl 채택안 — Spring Boot AutoConfiguration + `@ConditionalOnProperty`)
|
||||
- 인용하는 branch:
|
||||
- [[raw/branch-notes/feature-integration-adapter-templates]]
|
||||
- [[raw/branch-notes/feature-skeleton-package-blueprint-contract]]
|
||||
- 대안 그룹: **Group I — Integration adapter templates** (대안 5종)
|
||||
- 본 source의 위치: **대안 4: Java SPI (ServiceLoader) plugin architecture**
|
||||
- 인용하는 wiki: (미작성)
|
||||
Reference in New Issue
Block a user