좋은 기회로 Josh Long님이 Java21과 SpringBoot 3.x에 대해 소개해주는 밋업에 참여했다.
깊이 있는 내용을 다루기엔 시간이 짧았지만, Java21과 SpringBoot 3.x에서 제공해주는 새로운 기능들과 이 기능들의 활용 방법에 대한 아이디어를 얻을 수 있었다.
Java21의 DATA ORIENTED PROGRAMMIG 지원
요즘 인프라의 트랜드는 서비스를 작은 서버에 여러대에 올려 필요에 따라 scale out/in해 사용한다.
작은 서버에 애플리케이션을 실행시키기 때문에 하나의 서비스가 하는 역할이 작아졌고, 다른 서비스들과 메시지를 주고 받을 일이 많아졌다. 그리고 이러한 상황에 DATA ORIENTED PROGRAMMING 방식을 사용하면 목적에 맞는 코드를 작성할 수 있다.
JAVA21은 이런 트랜드를 지원하기 위해 4가지 기능을 통해 DATA ORIENTED PROGRAMIINGD을 지원한다.
- sealed types
- records
- pattern matching
- smart switch expressions
위 기능들을 사용하면 더욱 안전하고 빠른 코드를 작성할 수 있다.
Example Code
위 코드를 보면 Java21에서 제공하는 Sealed Type, Records, Pattern Matching, Smart Switch Expressions를 사용해 하나의 기능을 개발한 코드이다.
Records를 사용하면 반복적으로 만들어야 하는 함수를 만들지 않아도 돼 코드 수를 줄일 수 있다.
Switch 문을 사용하면 If문 보다 더 빠르게 동작하는 프로그램을 만들 수 있다.
Sealed Type과 Smart Switch Expression을 사용하면 컴파일 타임에 코드 오류를 찾을 수 있다. (아래는 그 예시이다.)
Spring Modulith
서비스에서 제공하는 기능이 많아질 수록 각 기능을 모듈화하고 모듈간 결합도를 낮추는 것이 중요하다. 모듈간 결합도가 강해지면 유지보수하기 힘든 코드가 된다. 이는 잦은 버그와 새로운 기능 출시 시간을 늘리는 악영향을 가져온다.
이때 Message를 이용하면 모듈간 결합도를 낮출 수 있다.
하지만 Message를 이용할 때 까다로운 부분이 존재한다. 메시지를 받아 처리하는 모듈에서 메시지 처리 중 비정상적으로 종료되면 메시지가 손실된다. 이는 전체 시스템 상태에 영향을 준다. 이때 Spring Modulith에서 제공하는 기능을 사용하면 누실된 메시지를 손 쉽게 재처리할 수 있다.
Example Code
application.properties
# spring modulith
spring.modulith.events.jdbc.schema-initialization.enabled=true
spring.modulith.republish-outstanding-events-on-restart=true
Java Code
Event를 받아 처리하는 모듈에서 @ApplicationModuleListener 기능을 이용해 메시지가 정상 처리되었는지 항상 확인하고, 정상처리되지 않았으면 재처리한다.
그 원리는 다음과 같다.
메시지가 오면 메시지의 상태를 DB에 저장한다.
그 후 메시지가 정상처리되면 메시지 상태를 업데이트해 메시지가 정상처리되었는지 체크한다.
만약 메시지가 정상처리되지 않아, COMPLETE_DATE COLUMN 값이 비어있다면, 메시지를 재처리 하도록 설정 할 수 있다.
이 외에도. Spring Modulith는 내 프로젝트의 모듈 구조에 Anti Pattern이 있는지를 테스트 코드를 통해 알려준다. 덤으로 모듈구조 문서까지 자동으로 만들어주는 기능을 제공한다.
Example Code
내 프로젝트 모듈구조에 안티패턴이 있다면, 테스트가 실패해 어디가 문제인지 알려준다. (A 모듈에서 공개하지 않은 기능을 B 모듈에서 사용할 경우)
추가로 내 프로젝트의 모듈 구조를 문서화해준다.
Spring AI
ChatGPT의 등장으로 생성형 AI의 활용도가 높아졌다. 요즘 나오는 대부분의 서비스는 생성형 AI를 이용한 기능을 제공한다.
Spring도 이런 트랜드에 맞춰 생성형 AI를 손쉽게 사용할 수 있는 방법을 지원한다.
Example Code
build.gradle
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
implementation 'org.springframework.ai:spring-ai-pgvector-store-spring-boot-starter'
application.properteis
# spring ai
spring.ai.openai.api-key=
spring.ai.openai.chat.options.model=gpt-4o
spring.ai.vectorstore.pgvector.initialize-schema=true
Java Code
@Configuration
class Assistant {
@Bean
ApplicationRunner runner(ChatClient chatClient) {
return args -> {
var content = chatClient
.prompt()
.user("do you have any neurotic dogs?")
.call()
.entity(DogAdoptionSuggestion.class);
System.out.println("reply [" + content + "]");
};
}
@Bean
ChatClient chatClient(
ChatClient.Builder builder,
DogRepository dogRepository,
VectorStore vectorStore
) {
// support system prompt
var system = """
You are an AI powered assistant to help people adopt a dog
from the adoption agency named Pooch Palace with locations in
Seoul, Las Vegas, Tokyo, Krakow, Singapore, Paris, London, and
San Francisco. If you don't know about the dogs housed at our particular
stores, then return a disappointed response suggesting we don't
have any dogs available.
""";
// support RAG(RETRIEVAL AUGMENTED GENERATION)
dogRepository.findAll().forEach(dog -> {
var dogument = new Document("id: %s, name: %s, description: %s".formatted(dog.id(), dog.name(), dog.description()));
vectorStore.add(List.of(dogument));
});
return builder
.defaultSystem(system)
.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
.build();
}
record DogAdoptionSuggestion(String name, String description, Integer id) {}
}
Spring AI의 ChatClient를 사용해 생성형 AI에게 질의할 수 있다.
또한 ChatClient는 System Prompt와 RAG를 지원한다. 덕분에 생성형 AI를 서비스에 맞게 손쉽게 커스터마이징 할 수 있다.
이에 더해 생성형 AI의 문자열 답변을 Java Entity로 변환해주는 기능도 제공한다.
Virtual Thread
Java21에 새로운 기능은 Virtual Thread가 나왔고, Spring Boot 3.x에서 속성하나로 Virtual Thread 기능을 활성화 시킬 수 있다.
application.properties
# activate virtual thread
spring.threads.virtual.enabled=true
Reactive 없이 비동기로 작업을 수행할 수 있는 놀라운 기술이라고 생각한다. 하지만 아직은 운영에 도입하기엔 여러 이슈들이 존재하는 것 같다.
GraalVM
GraalVM을 사용하면 Java를 jar 파일이 아닌 머신코드로 변환해 배포시간을 단축시킬 수 있다.
하지만 Build 시간이 너무 길어지고, Java의 모든 기능을 지원하지 않기 때문에 서비스에 적용하긴 이른거 같다.
마무리
이번 밋업을 통해 Java21 과 Spring Boot3.x에서 지원하는 기능을 자세히 알 수 있었다.
추가로 요즘 개발 트렌드에 대해서도 알 수 있었다. 인프라 관점에서는 작은 서버에 서버를 올려 필요할때 마다 Scale In/Out에 비용을 절감하는게 트랜드 같다. 이에 대한 영향으로 MSA가 나왔고 Event Driven Archiecture도 주목 받는 것 같다.
그리고 생성형 AI도 정말로 뜨거운 주제인 것 같다. 요즘 새로 나오는 서비스만 봐도 대부분의 서비스가 생성형 AI를 활용한 기능들을 제공한다. 그리고 개인적으로도 생성형 AI를 어떻게 사용하느냐에 따라 생산성에 큰 차이를 주는 것 같다.
(전체 코드가 궁금하다면, github 참고해주세요~)
Ref
[지금 무료] [인프런 X VMware Tanzu] Spring Boot 밋업 with Josh Long 강의 | 인프런 - 인프런
인프런 | 자바 챔피언, 스프링 개발자 애드버킷 Josh Long과 함께하는 특별한 Spring Boot 밋업!, 자바 챔피언, 스프링 개발자 애드버킷Josh Long과 함께하는 특별한 Spring Boot 밋업!인프런 퇴근길 밋업 with
www.inflearn.com
- https://github.com/joshlong/bootiful-spring-boot-2024/tree/main