Java 버전의 CDK는 Builder 패턴을 적극적으로 사용하며, 객체의 생성자와 메서드를 통해 인프라 간의 관계를 정의한다.
CDK App은 최상위 컨테이너이며, 그 아래 여러 Stack이 존재합니다. Stack 간에 객체(Resource)를 주고받으며 권한을 부여하는 것이 핵심이다.
이 예제에서는 두 개의 Stack을 만든다.
public class DatabaseStack extends Stack {
private final Table table;
public DatabaseStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// DynamoDB 테이블 생성
this.table = Table.Builder.create(this, "MyTable")
.partitionKey(Attribute.builder()
.name("id")
.type(AttributeType.STRING)
.build())
.build();
}
// 다른 스택에서 참조할 수 있도록 getter 제공
public Table getTable() {
return this.table;
}
}
public class ComputeStack extends Stack {
public ComputeStack(final Construct scope, final String id, final StackProps props, Table table) {
super(scope, id, props);
// Lambda 함수 생성
Function myFunction = Function.Builder.create(this, "MyLambda")
.runtime(Runtime.JAVA_17)
.handler("com.example.Handler")
.code(Code.fromAsset("lambda-codes.jar"))
.build();
// [핵심] Grant 사용: 테이블이 람다에게 읽기/쓰기 권한을 부여함
// 객체 지향적으로 "테이블아, 이 람다에게 권한 좀 줘"라고 명령하는 형태
table.grantReadWriteData(myFunction);
}
}
public class MyApp {
public static void main(final String[] args) {
App app = new App();
// 1. DB 스택 생성
DatabaseStack dbStack = new DatabaseStack(app, "DbStack", StackProps.builder().build());
// 2. Compute 스택 생성 (DB 스택의 테이블 객체를 생성자로 전달)
// 객체 지향의 의존성 주입(DI)과 유사한 패턴입니다.
new ComputeStack(app, "ComputeStack", StackProps.builder().build(), dbStack.getTable());
// 3. 앱 전체를 클라우드 포메이션으로 합성(Synthesis)
app.synth();
}
}
Table 객체를 넘겨줄 때 타입이 맞지 않으면 컴파일 에러가 발생합니다. 이는 YAML 설정에서 발생할 수 있는 참조 오류를 사전에 차단한다.DatabaseStack에서 테이블을 private으로 두고 필요한 객체만 getter로 노출하는 방식은 전형적인 Java의 캡슐화 원칙을 따른다.App은 위 예제의 main 메서드에서 보듯, 서로 다른 Stack들을 하나로 묶고 그들 사이의 데이터(여기서는 table 객체)가 흐르도록 조율하는 최상위 오케스트레이터.App은 도화지이고, Stack은 그 위에 그리는 커다란 그림 영역이며, 그 안의 리소스들을 Grant라는 문법을 통해 서로 유기적으로 연결하는 것.