지금 배우기 좋은 자바 마이크로프레임워크 7가지
컨텐츠 정보
- 조회 414
본문
자바 마이크로프레임워크는 일반적으로 가벼움과 미니멀리즘을 추구하며 성능과 클라우드 네이티브 기능, 개발자 경험에 중점을 둔다는 특징이 있다. 가벼운 웹 애플리케이션을 빌드하는 데 적합하도록 설계되고, 특히 마이크로서비스 아키텍처와 잘 맞는다. 가장 보편적인 선택은 스프링 부트(Spring Boot)지만 다양한 요구사항에 맞는 다양한 프레임워크가 있다. 여기서는 기능과 단순함의 조합이 돋보이는 7개 자바 마이크로프레임워크를 간략히 살펴본다.
여기서 다룰 프레임워크를 요약하면 다음과 같다. 스프링 부트는 참조를 위해 포함했다.
| 프레임워크 | 인기도(깃허브 별점 개수) | 주요 강점 | 깃허브 페이지 |
| 스프링 부트 | ~7만 8,200개 | 사실상의 표준, 가벼운 스프링 | https://github.com/spring-projects/spring-boot |
| 쿼커스 | ~1만 4,800개 | 시작 속도 빠름, 낮은 메모리 사용량 | https://github.com/quarkusio/quarkus |
| Vert.x | ~1만 4,600개 | 높은 동시성, 논블로킹 | https://github.com/eclipse-vertx/vert.x |
| 케이터 | ~1만 3,900개 | 코루틴, 유연성 | https://github.com/ktorio/ktor |
| 드롭위저드 | ~8,400개 | 안정성, 바로 사용 가능 | https://github.com/dropwizard/dropwizard |
| 자발린 | ~8,000개 | 극한의 간소함, 작은 API | https://github.com/javalin/javalin |
| 마이크로넛 | ~6,300개 | 리플렉션 비사용, 효율적 | https://github.com/micronaut-projects/micronaut-core |
| 헬리돈 | ~3,700개 | 오라클이 후원, 표준 기반 | https://github.com/helidon-io/helidon |
성능에 대해
여기서 다루는 여러 자바 마이크로프레임워크는 그랄VM(GraalVM)을 통해 네이티브 바이너리를 생성한다. 이렇게 생성된 바이너리는 대상 플랫폼에 맞게 고도로 최적화돼 빠른 시작과 종료, 효율적인 메모리 사용, 그리고 사전 컴파일(AOT)을 포함한 런타임 성능을 보장한다. 이와 같은 특성은 특히 서버리스 환경과 같이 수요 변화에 따라 프로세스가 빈번하게 시작되고 종료되는 프로덕션 환경에서 큰 장점이 된다.
잘 설계된 자바 애플리케이션을 그랄VM을 사용해 바이너리로 컴파일하면 현존하는 런타임 중 가장 뛰어난 성능을 얻을 수 있다. 그랄VM은 SDKMan을 통해 간단히 설치할 수 있다. 예를 들어 sdk install java 24.0.2-graalce 같은 명령을 사용하면 된다.
현대 자바와 JVM 언어의 또 다른 강력한 기능은 바로 가상 스레드다. 이 글에서 다루는 모든 프레임워크에도 가상 스레드와의 연결 고리가 있다. 가상 스레드는 안정성 검증을 거쳐 자바 21에서 프로덕션에 적합한 기능으로 포함됐다.
이제 각 프레임워크를 자세히 살펴보자.
쿼커스
쿼커스(Quarkus)는 현대적인 클라우드 네이티브 프레임워크로 뛰어난 개발 모드, 많은 기능을 플러그인 방식으로 제공하는 아키텍처를 갖췄으며 그랄VM이나 만드렐(Mandrel)을 사용한 간편한 네이티브 빌드를 제공한다. 스프링에 익숙하면서 빠른 시작 시간과 네이티브 컴파일을 원하는 개발자에게 특히 적합하다.
또한 쿼커스는 애플리케이션 스캐폴딩을 위한 명령줄 인터페이스(CLI)도 제공한다. sdk install quarkus로 쿼커스를 설치한 다음 quarkus create를 사용해 앱을 스캐폴딩할 수 있다. 앱을 개발 모드로 실행하면(quarkus dev) 코드 변경 사항이 즉시 배포되며 개발 콘솔도 제공된다.
그 외에 쿼커스는 로깅, 메트릭, 인증, 데이터스토어와 같은 다양한 확장을 제공한다. UI를 사용해 확장을 관리하고 CLI를 사용해 추가하거나 제거할 수도 있다.
쿼커스는 Vert.x를 통해 명령형 프로그래밍과 리액티브 프로그래밍 스타일을 모두 지원하므로 하나의 애플리케이션 안에서 두 가지 프로그래밍 스타일을 함께 사용할 수 있다. 또한 엔드포인트에서 가상 스레드도 직접 지원한다.
그 외에 쿼커스는 자카르타(Jakarta) EE 표준 기반의 CDI 주입 프레임워크를 제공하고, 이러한 종속성을 빌드 타임에 해소해 런타임 해소 시 발생하는 성능 저하를 방지한다. 이렇게 해서 네이티브 빌드와 JVM 빌드에서 모두 성능이 향상된다.
다음은 쿼커스를 사용한 간단한 엔드포인트다.
import jakarta.ws.rs.GET;import jakarta.ws.rs.Path;import jakarta.ws.rs.Produces;import jakarta.ws.rs.core.MediaType;@Path("/hello")public class GreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return "Hello from InfoWorld!"; }}쿼커스는 개발을 지원하면서 필요에 따라 부가적인 기능을 제공하는 방식으로 균형 잡힌 사용 경험을 구현한다. 간단하면서도 다양한 기능을 수행할 수 있는, 개발자 경험을 중시하는 프레임워크를 원한다면 쿼커스는 가치 있는 선택이다.
Vert.x
Vert.x는 자바 환경에서 가장 먼저 등장해 가장 성숙한 단계에 이른 리액티브 프레임워크 중 하나다. 고성능 리액티브 파이프라인을 구축하는 데 필요한 요소를 모두 갖춘 풀스케일 리액티브 컨테이너로, 대규모 데이터 스트림 처리에 최적화된 성능이 필요한 프로젝트에 특히 적합하다.
Vert.x는 전통적인 의미의 프레임워크보다는 리액티브 스트림을 구성하기 위한 정교한 툴 모음에 가까운데, 이 특성은 최대한의 유연성을 원하는 경우 장점이 된다. 쿼커스를 포함한 다양한 툴과 프레임워크가 Vert.x를 기반으로 한다. Vert.x는 툴킷으로 사용하든 프레임워크로 사용하든 탁월하고 폭넓은 기능을 제공한다.
Vert.x 기술은 이벤트 루프 아키텍처를 기반으로 하며 CPU 리소스의 유휴 상태를 최소화하도록 설계됐다. 이 아키텍처 위에서 Vert.x는 비동기 프로그래밍을 처리하기 위한 다양한 방법을 제공한다. 또한 방대한 연산자와 정교한 리액티브 구성을 지원하는 Rx자바(RxJava)도 지원한다.
Vert.x는 이벤트 루프를 사용하면서도 단일 스레드로 제한되지 않으므로 비동기 처리와 멀티스레딩, 두 가지 모두 가능하다. 이를 멀티 리액터(multi-reactors)라고 하며, 일반적으로 CPU 코어당 하나의 이벤트 스레드를 제공한다(노드(Node) 등에 비해 큰 장점). 또한 단일 노드 내에서의 확장을 위해 앱이 버티클(verticles)이라고 하는 핸들러 클래스의 인스턴스를 여러 개 생성하는 방식을 세밀하게 조정할 수 있다.
Vert.x는 코틀린과도 호환되므로 비동기 이벤트 처리를 위해 코틀린 코루틴을 네이티브로 사용할 수 있다. 그 외에도 Vert.x가 지원하는 언어로는 그루비(Groovy), 루비(Ruby), 자바 등이 있고 웹소켓을 통해 클라이언트 측 자바스크립트도 지원한다.
Vert.x 엔드포인트의 예는 다음과 같다.
import io.vertx.core.AbstractVerticle;import io.vertx.core.Promise;public class MainVerticle extends AbstractVerticle { @Override public void start(Promise startPromise) throws Exception { vertx.createHttpServer().requestHandler(req -> { req.response() .putHeader("content-type", "text/plain") .end("Hello from Vert.x!"); }).listen(8888, http -> { if (http.succeeded()) { startPromise.complete(); System.out.println("HTTP server started on port 8888"); } else { startPromise.fail(http.cause()); } }); }}Vert.x는 마이크로서비스 애플리케이션의 노드 내부, 그리고 노드 간 통신을 위한 정교한 이벤트 버스도 제공한다. 이벤트 버스는 Vert.x 노드를 위한 가벼운 분산 메시징 시스템이라고 생각하면 된다. 영구적인 메시지 브로커로 격상해야 한다면 래빗MQ(RabbitMQ) 등 Vert.x가 지원하는 여러 통합 기능을 사용하면 된다.
Vert.x는 많은 인기 있는 데이터베이스(예를 들어 몽고DB)를 위한 잘 설계된 고성능 커넥터, 그리고 이러한 데이터스토어와 통합되는 권한 부여 및 인증 구성요소도 갖췄다.
Vert.x는 스프링 이니셜라이저(Spring Initializr)와 마찬가지로 새로운 앱을 구성하기 위한 웹 기반 툴을 제공한다.
실시간 데이터 스트림을 소비, 연결, 생산해야 한다면 Vert.x는 훌륭한 선택이다. 확실히 자바를 위한 가장 발전되고 성숙한 리액티브 플랫폼 중 하나다.
케이터
케이터(Ktor)는 JVM의 장점을 온전히 활용할 수 있는 현대적 언어인 코틀린을 위해 젯브레인스(JetBrains)가 만든 전용 프레임워크다. 케이터는 웹 개발을 위해 폭넓게 조합 가능한 기능을 제공하며, 비동기 프로그래밍을 위해 코틀린 코루틴을 활용한다. 코틀린에서 웹 앱을 구축하기 위한 공식 메커니즘이다.
케이터 CLI에는 필요한 모든 기능을 갖춘 생성 마법사가 포함돼 있어 이를 사용해 새 애플리케이션을 시작할 수 있다(ktor new).
케이터는 ‘피처(feature)’로 불리는 플러그인을 지원하는 모듈형 프레임워크다. 옵션에는 종속성 주입(dependency injection, DI) 엔진(koin)을 비롯해 모니터링, 관리, 데이터스토어 커넥터, 보안과 같은 필수 기능이 포함된다. 이러한 모든 요소가 케이터의 통합 프레임워크에서 제공된다.
케이터의 기능은 강력하다. 예를 들어 HTML을 생성하기 위한 코틀린 DSL은 데이터 기반 마크업을 생성하기 위한 직관적이고 간단한 방법이다. 케이터의 가장 강력한 기능은 코틀린 코루틴을 암시적으로 사용해서 논블로킹 비동기 연산을 동기 연산처럼 보이게 만드는 것이다. 예를 들어 아래 코드에서 client.get() 호출은 블로킹처럼 보이지만 내부적으로는 완전히 비동기적으로 동작한다.
import io.ktor.client.*//... other importsrouting { get("/") { try { // Implicit coroutine use: val book = client.get("https://anapioficeandfire.com/api/books/1").body() call.respond(book) } catch (e: Exception) { call.respondText("Error fetching book: ${e.message}") } }}케이터는 모든 종류의 서버 측 코틀린 기능을 구축하기 위한 다재다능한 툴 모음이다. 웹 서버에 코루틴을 도입한 것으로 가장 잘 알려져 있지만 사실 어떤 역할이든 잘 해낼 수 있다. 누구나 사용할 수 있지만 특히 모든 기능을 완비한 웹 애플리케이션 프레임워크를 찾는 코틀린 개발자에게 최적의 선택지다.
드롭위저드
드롭위저드(Dropwizard)는 클라우드 환경의 현대적인 RESTful 서비스를 위해 설계된 성숙하고 가벼운 프레임워크다. 애플리케이션 독립 실행이 가능하도록 애플리케이션 내부에 제티(Jetty) 서버를 내장하며, JSON을 위한 잭슨(Jackson)과 엔드포인트 정의를 위한 저지(Jersey)를 함께 제공한다. 이와 같은 기본적인 구성에서 출발해 지속성 및 기타 일반적인 애플리케이션 요구사항을 처리하기 위한 구성요소를 추가할 수 있다.
드롭위저드의 가장 매력적인 기능 중 하나는 드롭위저드 팀이 만든 메트릭스(Metrics) 라이브러리를 기반으로 한 내장된 운영 메트릭이다. 메트릭스는 필요한 모든 기능을 갖춘 모니터링 툴로, 애플리케이션과 통합되며 일반적인 라이브러리 종속 항목, 그리고 그래파이트(Graphite) 같은 백엔드와도 통합된다.
드롭위저드는 기본적으로 다른 여러 프로젝트를 사용하기 쉬운 하나의 패키지로 묶는 ‘접착제’ 프레임워크라고 할 수 있다. 사용자는 다양한 프로젝트를 직접 오케스트레이션하지 않고도 지능적으로 사용할 수 있다.
다음은 롭위저드에서의 엔드포인트 매핑 예시다.
import jakarta.ws.rs.GET;import jakarta.ws.rs.Path;import jakarta.ws.rs.Produces;import jakarta.ws.rs.core.MediaType;@Path("/hello")@Produces(MediaType.TEXT_PLAIN)public class HelloResource { @GET public String sayHello() { return "Hello from InfoWorld!"; }}여기서 볼 수 있듯이 드롭위저드는 경로 처리를 위한 자카르타(Jakarta) 프로젝트인 저지(Jersey)에 대부분의 작업을 위임한다.
드롭위저드는 동종 최고의 여러 툴을 클라우드를 지원하는 가벼운 통합 프레임워크로 모아서 제공한다. 또한 안정성과 모니터링에 중점을 두므로 이러한 부분을 우선시한다면 완벽한 선택이다.
자발린
자발린(Javalin)은 극한의 간결함과 직관성을 원하는 개발자를 위한 마이크로프레임워크다.
자발린은 JVM을 위한 최초의 오픈소스 마이크로프레임워크인 스파크자바(SparkJava)의 코드를 계승하며, 단순성과 유연성에 중점을 둔다. 많은 현대적 프레임워크와 달리 자발린은 방향성을 지양하고(unopinionated), 프레임워크보다는 라이브러리에 가깝다. 어떻게 사용할지는 전적으로 개발자에게 달려 있다. 자발린은 숨겨진 종속성을 피하고 모든 것을 코드에 명시적으로 드러내는 데 중점을 두므로 DI 또는 코드 스캐닝을 제공하지 않는다. 자발린 서버는 대체로 매우 간결하다.
자발린도 드롭위저드와 마찬가지로 제티 서버를 내장해서 안정성과 성능으로 잘 알려진 익숙한 HTTP 플랫폼을 제공한다.
또한 자바와 코틀린을 모두 지원하는 다언어 프레임워크다. 다음은 코틀린으로 작성한 간단한 Hello World 서버 예시다.
import io.javalin.Javalinfun main() { val app = Javalin.create(/*config*/) .get("/") { ctx -> ctx.result("Hello World") } .start(7070)}자바를 사용한 예시는 다음과 같다.
import io.javalin.Javalin;public class App { public static void main(String[] args) { var app = Javalin.create() .get("/", ctx -> ctx.result("Hello World")) .start(7070); }}유창한 메서드 체이닝과 깔끔한 코드를 확인할 수 있으며, 덕분에 서버 정의와 엔드포인트를 함께 기술할 수 있다.
자발린은 쓸데없는 부가적 요소나 종속성 구문을 지양한다. 필요한 일을 수행할 수 있는 최소한의 프레임워크를 찾는다면 자발린이 최적의 프레임워크가 될 수 있다.
마이크로넛
마이크로넛(Micronaut)은 시작 시간이 가장 중요한 요소일 때, 또는 마이크로서비스와 서버리스 앱을 구축하기 위해 다중 언어 풀스택 프레임워크가 필요할 때 좋은 선택이다. 리플렉션 없이 성능과 종속성 주입이 기능한 AOT 컴파일러를 제공한다. JVM에서 실행할 수 있으며, 그랄VM을 통해 네이티브 이미지로 컴파일할 수도 있다.
마이크로넛의 IoC(inversion of control) 컨테이너는 모든 종속성을 컴파일 중에 해소하는 방식으로 작동하며, 이를 통해 마이크로서비스에 필수적인 빠른 시작 시간이 가능해진다. 또한 마이크로넛의 이러한 설계는 종속성 주입의 메모리 사용량도 줄여준다.
마이크로넛은 자바, 그루비, 코틀린을 지원하는 다언어 프레임워크이며 향후 스칼라도 지원할 계획이다.
마이크로넛은 클라우드에 맞춰 설계됐다. 서비스 검색을 위해 쿠버네티스와 같은 공급자, 그리고 예거(Jaeger)와 같은 트레이싱과 자동으로 통합된다. 따라서 하드코딩을 피하고, 구성을 통한 자동화된 검색과 트레이싱을 활용해 마이크로서비스를 설계할 수 있다. 또한 컨설(Consul)과 같은 분산 구성도 지원한다.
마이크로넛은 내장 데이터스토어 커넥터를 갖추고 데이터 액세스 계층을 지원하며 오픈API 기술 명세서도 지원한다.
고급 기능을 갖추었음에도 마이크로넛의 엔드포인트는 간결하고 읽기 쉽다.
import io.micronaut.http.annotation.Controller;import io.micronaut.http.annotation.Get;@Controller("/hello")public class HelloController { @Get("/{name}") public String hello(String name) { return "Hello, " + name; }}이름이 시사하듯 마이크로넛은 마이크로서비스에 이상적이며, 개발 과정에서 최대한의 편의성을 제공하는 데 목표를 둔다. 자바를 위한 마이크로서비스 프레임워크 중에서 가장 정교하게 다듬어진 프레임워크라고 할 수 있다
헬리돈
헬리돈(Helidon)은 자바 표준을 준수하면서 엔터프라이즈를 지원하고자 하고 프레임워크 유형을 선택할 수 있는 옵션도 원할 경우 유력하게 고려할 만한 선택지다.
헬리돈은 이 글에서 다룬 프레임워크 중에서 가장 최신이며 오라클의 공식 프로젝트이기도 하다. 처음부터 가상 스레드와 빌드 타임 종속성 주입(마이크로넛과 비슷)에 중점을 두고 설계됐다. 최근에는 AI를 위한 기능도 추가됐다.
헬리돈은 다음과 같은 두 가지 형태로 제공된다.
- SE(Standard Edition) : 함수형 프로그래밍(FP) 마이크로서비스를 구축하기 위한 기본적인 툴 모음이다. 극도로 작은 메모리 사용량과 빠른 시작에 초점을 둔다. 헬리돈 4부터는 기본적으로 가상 스레드를 사용한다.
- MP(MicroProfile) : SE 위에 부가 기능을 얹어 제공한다. 종속성 주입과 함께 JAX-RS, JSON-P와 같은 몇몇 자카르타 EE 구성요소가 추가된다.
헬리돈 SE는 기본 개념과 기능 측면에서 자발린과, 헬리돈 MP는 쿼커스와 비슷하다. 가상 스레드 도입은 복잡한 동시성 모델이 제거됐음을 의미한다. 즉, 애플리케이션 노드를 이해하고 관리하기가 더 쉬워졌다.
다음은 헬리돈 SE의 엔드포인트 예시다.
import io.helidon.webserver.WebServer;import io.helidon.webserver.http.HttpRouting;public class Main {public static void main(String[] args) {HttpRouting routing = HttpRouting.builder().get("/hello", (req, res) -> res.send("Hello from InfoWorld!")).build();WebServer.builder() .routing(routing) .port(8080) .build() .start();}}헬리돈의 핵심 강점은 오라클 표준이라는 점, 그리고 모델 선택권을 제공해서 개발자가 SE를 통해 간결한 DIY로 갈지, MP를 통해 명확한 방향성을 가진 올인원 프레임워크로 갈지를 결정할 수 있게 해준다는 점이다.
결론
자바는 간단한 API부터 정교한 마이크로서비스 클러스터, 서버리스 배포, 풀스택 애플리케이션에 이르기까지 모든 것을 현대 클라우드에서 구축하기 위한 폭넓은 선택 옵션을 제공한다. 이 글에서 다룬 자바 마이크로프레임워크는 모두 충실한 기능을 제공하므로 넓은 선택의 폭에 질릴 필요는 없다. 우선 요구사항과 맞아 보이는 한두 가지를 선택해 코드를 조금 다뤄본 다음 최선의 프레임워크를 선택하면 된다. 여기서 다룬 여러 프레임워크의 좋은 점은 개발자 경험을 중시한다는 것이다. 따라서 어떤 경험이 자신에게 가장 적합한지 개발자 스스로 결정할 수 있다.
dl-itworldkorea@foundryco.com
관련자료
-
링크
-
이전
-
다음







