포트
포트는 다른 시스템 호출을 YAML 로 선언합니다. 생성기는 인터페이스를 쓰고, 실행할 때 프록시 팩토리가 그것을 구현합니다. 손으로 쓸 어댑터 클래스가 없습니다.
헥사고날로 말하면 아웃바운드 포트입니다: 애플리케이션은 인터페이스만 알고 기술은 밖에 있습니다.
| 방향 | 무엇 | 네임스페이스 |
|---|---|---|
| 인바운드 | OrderUseCase - hexagonal-springboot 가 생성 | inboundPort |
| 아웃바운드 (이 장) | port: - HTTP, DBMS, gRPC | port |
| 아웃바운드 (영속) | OrderRepositoryPort - DDD 번들이 생성 | domainRepository |
| 타입 | 용도 | 실행할 때 |
|---|---|---|
http | 다른 시스템의 REST API | HttpServiceProxyFactory - 또는 httpPort: spring 이면 Spring 의 @HttpExchange 클라이언트 |
dbms | DB 에서 SQL 실행 | DbmsServiceProxyFactory |
proto | gRPC | 생성되는 .proto 서비스 정의 |
모양
port:
ServiceName:
meta: <type> [options]
methods:
methodName:
meta: method [annotations]
params:
paramName: ParamType
return: ReturnType
인터페이스가 놓이는 곳
namespace:
port: com.example.application.port.out
domain 아래에 두지 마세요: 계약이 application DTO 로 쓰이고, 페이징하면 Spring 의 Page 도 씁니다 -
애플리케이션의 포트입니다. 도메인 서비스의 uses: 에 적으면 경고와 함께 무시됩니다.
프록시 등록: 자동 구성
3.0.261023 부터 런타임 프록시(기본 방식의 HTTP 포트, DBMS 포트)는 애플리케이션 클래스에 아무것도 적지 않아도 빈이 됩니다.
런타임 라이브러리(elasticore-springboot3 / -springboot4)가 Spring Boot 자동 구성
io.elasticore.springboot.autoconfigure.ElastiCoreAutoConfiguration 을 가지고 있습니다:
@SpringBootApplication // 이것만 - 포트는 이 패키지와 그 아래에서 찾습니다
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
자동 구성은 @SpringBootApplication 클래스의 패키지와 그 아래 - Spring Boot 가 엔티티와 리포지터리를 찾는 곳 - 에서 포트
(@ExternalService, @DbmsService)를 찾으므로, 그 클래스를 띄우는 @SpringBootTest 도 포트 빈을 받습니다. 포트를 찾았을 때만
다음을 등록합니다:
- 포트
DbTransactionGateway(DBMS 포트의 SQL 을 실행) -EntityManagerFactory가 하나이거나@Primary하나가 있을 때ApplicationContextProvider- 기동 배너
포트가 없는 애플리케이션에는 아무것도 등록하지 않습니다.
@EnableElastiCore는 그대로 동작합니다. 함께 있어도 포트와 빈은 한 번씩만 등록됩니다. 지울 필요는 없습니다.- 이미 있는 빈이 이깁니다:
@ComponentScan("io.elasticore.springboot3"), 또는 포트나DbmsSqlExecutor에 직접 선언한@Bean. 프록시를 감싸는@Primary빈을 두면 프록시는 남습니다(@Qualifier("CourierPort")). - 애플리케이션 클래스의 패키지 밖에 있는 포트는 찾지 못합니다.
@SpringBootApplication(scanBasePackages = ...)로 더한 패키지도 마찬가지입니다.@AutoConfigurationPackage(basePackages = ...)(엔티티·리포지터리를 찾는 곳도 넓힙니다), 그 패키지의 클래스에 붙인@EnableElastiCore, 또는@Bean으로 등록하세요. 등록되지 않은 포트는 주입할 수 없습니다:No qualifying bean of type 'ShopReportService'. - 단순 이름이 같은 포트(
shop.NotificationPort,billing.NotificationPort)는 모두 전체 클래스 이름으로 등록되고 경고가 남습니다. 타입으로 주입하거나@Qualifier("<전체 클래스 이름>")을 쓰세요. EntityManagerFactory가 둘 이상이고@Primary가 없으면 실행기를 만들지 않습니다. 하나를@Primary로 하거나DbmsSqlExecutor빈을 선언하세요.- 끄기:
elasticore.autoconfigure.enabled=false- 이때는@EnableElastiCore를 씁니다. 배너만 끄려면elasticore.banner.enabled=false. - Spring Boot 없이 띄우는 Spring 컨텍스트는 여전히
@EnableElastiCore가 필요합니다 (io.elasticore.springboot3.EnableElastiCore- Boot 4 런타임도 같은 패키지).
프록시는 빈(DBMS 실행기, HTTP 인증·변환기)을 자기가 만들어진 빈 팩토리에서 찾으므로, 컨텍스트를 여럿 띄우는 테스트에서도 서로의 빈을 보지 않습니다.
3.0.261022-rc1 까지는 @EnableElastiCore 가 있어야 합니다: 없으면 포트가 빈이 되지 않고,
@ComponentScan("io.elasticore.springboot3") 로도 등록되지 않습니다.
httpPort: spring 포트는 Spring 의 클라이언트라 둘 다 필요 없습니다.
gRPC
port:
UserGrpcService:
meta: proto @server @client
methods:
getUser:
meta: method -- 사용자 조회
params:
input: UserProtoInput
return: UserProtoOutput
@server 는 서버 쪽, @client 는 클라이언트 쪽을 생성하고, .proto 서비스 정의가 생성됩니다.