Quarkus 从入门到精通完整指南Q
1. Quarkus 简介
Quarkus是一个为云原生和容器化环境设计的Java框架,专门为GraalVM和OpenJDK HotSpot优化。它提供了超快的启动时间、极低的内存占用和高性能。
核心特性
- 超快启动时间:毫秒级启动
- 低内存占用:比传统Java应用减少70%+内存使用
- 原生编译支持:通过GraalVM编译为原生可执行文件
- 开发者友好:热重载、统一配置、扩展生态系统
2. 环境准备
必要工具
# Java 17或更高版本
java --version# Maven 3.8.6+或Gradle 7.5+
mvn --version# 可选:GraalVM(用于原生编译)
# 可选:Docker(用于容器化部署)
IDE推荐
- IntelliJ IDEA(推荐)
- Visual Studio Code + Quarkus扩展
- Eclipse + Quarkus工具
3. 第一个Quarkus项目
3.1 使用Maven创建项目
mvn io.quarkus.platform:quarkus-maven-plugin:3.5.0:create \-DprojectGroupId=com.example \-DprojectArtifactId=getting-started \-Dextensions="resteasy-reactive-jackson"
3.2 项目结构
getting-started/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ └── GreetingResource.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ └── java/
│ └── com/example/
│ ├── GreetingResourceTest.java
│ └── NativeGreetingResourceIT.java
├── pom.xml
└── README.md
3.3 第一个REST API
// src/main/java/com/example/GreetingResource.java
package com.example;import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
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 RESTEasy Reactive";}@GET@Path("/{name}")@Produces(MediaType.TEXT_PLAIN)public String greeting(@PathParam("name") String name) {return "Hello " + name + "!";}
}
3.4 运行项目
# 开发模式(支持热重载)
mvn quarkus:dev# 访问 http://localhost:8080/hello
# 访问 http://localhost:8080/hello/world
4. 核心概念详解
4.1 依赖注入(CDI)
// 服务类
@ApplicationScoped
public class GreetingService {public String generateGreeting(String name) {return "Hello " + name + " from service!";}
}// 在Resource中注入
@Path("/greeting")
public class GreetingResource {@InjectGreetingService greetingService;@GET@Path("/{name}")@Produces(MediaType.TEXT_PLAIN)public String greeting(@PathParam("name") String name) {return greetingService.generateGreeting(name);}
}
4.2 配置管理
# src/main/resources/application.properties
greeting.message=Hello
greeting.suffix=from Quarkus!
server.port=8080
// 配置注入
@Path("/config")
public class ConfigResource {@ConfigProperty(name = "greeting.message")String message;@ConfigProperty(name = "greeting.suffix", defaultValue = "World")String suffix;@GET@Produces(MediaType.TEXT_PLAIN)public String getConfig() {return message + " " + suffix;}
}
4.3 配置类
@ConfigMapping(prefix = "greeting")
@ConfigProperties
public interface GreetingConfig {String message();String suffix();Optional<String> name();
}// 使用配置类
@Path("/typed-config")
public class TypedConfigResource {@InjectGreetingConfig config;@GET@Produces(MediaType.TEXT_PLAIN)public String getGreeting() {return config.message() + " " + config.suffix();}
}
5. 数据库集成
5.1 添加Hibernate ORM依赖
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
5.2 数据库配置
# src/main/resources/application.properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=postgres
quarkus.datasource.password=password
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydbquarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true
5.3 实体类
// src/main/java/com/example/entity/Person.java
package com.example.entity;import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;@Entity
public class Person extends PanacheEntity {public String firstName;public String lastName;public String email;// 静态方法查询public static Person findByEmail(String email) {return find("email", email).firstResult();}public static List<Person> findByLastName(String lastName) {return list("lastName", lastName);}
}
5.4 Repository模式
// Repository接口
@ApplicationScoped
public class PersonRepository implements PanacheRepository<Person> {public Person findByEmail(String email) {return find("email", email).firstResult();}public List<Person> findByLastName(String lastName) {return list("lastName", lastName);}public void deleteByEmail(String email) {delete("email", email);}
}
5.5 REST CRUD操作
@Path("/persons")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PersonResource {@InjectPersonRepository personRepository;@GETpublic List<Person> getAllPersons() {return Person.listAll();}@GET@Path("/{id}")public Person getPerson(@PathParam("id") Long id) {return Person.findById(id);}@POST@Transactionalpublic Response createPerson(Person person) {person.persist();return Response.status(Response.Status.CREATED).entity(person).build();}@PUT@Path("/{id}")@Transactionalpublic Person updatePerson(@PathParam("id") Long id, Person person) {Person existingPerson = Person.findById(id);if (existingPerson == null) {throw new WebApplicationException("Person not found", 404);}existingPerson.firstName = person.firstName;existingPerson.lastName = person.lastName;existingPerson.email = person.email;return existingPerson;}@DELETE@Path("/{id}")@Transactionalpublic Response deletePerson(@PathParam("id") Long id) {boolean deleted = Person.deleteById(id);if (deleted) {return Response.status(204).build();}return Response.status(404).build();}
}
6. 反应式编程
6.1 添加反应式依赖
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
6.2 反应式REST API
@Path("/reactive")
public class ReactiveResource {@GET@Path("/hello")@Produces(MediaType.TEXT_PLAIN)public Uni<String> hello() {return Uni.createFrom().item("Hello Reactive World!").onItem().delayIt().by(Duration.ofSeconds(1));}@GET@Path("/items")@Produces(MediaType.APPLICATION_JSON)public Multi<String> getItems() {return Multi.createFrom().items("item1", "item2", "item3").onItem().call(item -> Uni.createFrom().voidItem().onItem().delayIt().by(Duration.ofMillis(100)));}
}
6.3 反应式数据库操作
@ApplicationScoped
public class ReactivePersonService {@InjectPgPool client;public Uni<List<Person>> findAll() {return client.query("SELECT * FROM person").execute().onItem().transform(rows -> {List<Person> persons = new ArrayList<>();for (Row row : rows) {Person person = new Person();person.id = row.getLong("id");person.firstName = row.getString("firstName");person.lastName = row.getString("lastName");person.email = row.getString("email");persons.add(person);}return persons;});}public Uni<Person> save(Person person) {return client.preparedQuery("INSERT INTO person (firstName, lastName, email) VALUES ($1, $2, $3) RETURNING id").execute(Tuple.of(person.firstName, person.lastName, person.email)).onItem().transform(rows -> {Long id = rows.iterator().next().getLong("id");person.id = id;return person;});}
}
7. 安全性
7.1 添加安全扩展
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-oidc</artifactId>
</dependency>
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-keycloak-authorization</artifactId>
</dependency>
7.2 基本认证配置
quarkus.http.auth.basic=true# 用户配置(仅用于开发)
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.alice=alice
quarkus.security.users.embedded.roles.alice=user
quarkus.security.users.embedded.users.admin=admin
quarkus.security.users.embedded.roles.admin=admin
7.3 安全注解
@Path("/secured")
public class SecuredResource {@GET@Path("/public")@PermitAllpublic String publicResource() {return "This is public";}@GET@Path("/user")@RolesAllowed("user")public String userResource(@Context SecurityContext securityContext) {return "Hello " + securityContext.getUserPrincipal().getName();}@GET@Path("/admin")@RolesAllowed("admin")public String adminResource() {return "Admin only resource";}
}
7.4 JWT配置
# JWT配置
quarkus.oidc.auth-server-url=https://your-keycloak-server/auth/realms/your-realm
quarkus.oidc.client-id=your-client-id
quarkus.oidc.credentials.secret=your-client-secret
8. 测试
8.1 单元测试
@QuarkusTest
public class GreetingResourceTest {@Testpublic void testHelloEndpoint() {given().when().get("/hello").then().statusCode(200).body(is("Hello from RESTEasy Reactive"));}@Testpublic void testGreetingEndpoint() {given().pathParam("name", "Quarkus").when().get("/hello/{name}").then().statusCode(200).body(is("Hello Quarkus!"));}
}
8.2 集成测试
@QuarkusTest
@TestProfile(DatabaseTestProfile.class)
public class PersonResourceTest {@Test@Transactionalpublic void testCreatePerson() {Person person = new Person();person.firstName = "John";person.lastName = "Doe";person.email = "john@example.com";given().contentType("application/json").body(person).when().post("/persons").then().statusCode(201).body("firstName", equalTo("John")).body("lastName", equalTo("Doe"));}
}
8.3 测试配置文件
public class DatabaseTestProfile implements QuarkusTestProfile {@Overridepublic Map<String, String> getConfigOverrides() {return Map.of("quarkus.datasource.db-kind", "h2","quarkus.datasource.jdbc.url", "jdbc:h2:mem:testdb","quarkus.hibernate-orm.database.generation", "drop-and-create");}
}
9. 构建和部署
9.1 JVM模式构建
# 打包应用
mvn clean package# 运行JAR
java -jar target/quarkus-app/quarkus-run.jar
9.2 原生编译
# 构建原生镜像(需要GraalVM)
mvn clean package -Pnative# 运行原生可执行文件
./target/getting-started-1.0.0-SNAPSHOT-runner
9.3 Docker容器化
# Dockerfile.jvm
FROM registry.access.redhat.com/ubi8/openjdk-17:1.15
COPY target/quarkus-app/lib/ /deployments/lib/
COPY target/quarkus-app/*.jar /deployments/
COPY target/quarkus-app/app/ /deployments/app/
COPY target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
# 构建Docker镜像
docker build -f Dockerfile.jvm -t my-app:latest .# 运行容器
docker run -p 8080:8080 my-app:latest
9.4 原生Docker镜像
# Dockerfile.native
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.7
WORKDIR /work/
RUN chown 1001 /work && chmod "g+rwX" /work && chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
10. 高级特性
10.1 健康检查
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-smallrye-health</artifactId>
</dependency>
@ApplicationScoped
public class DatabaseHealthCheck implements HealthCheck {@InjectDataSource dataSource;@Overridepublic HealthCheckResponse call() {try (Connection connection = dataSource.getConnection()) {boolean isValid = connection.isValid(2);return HealthCheckResponse.named("Database connection health check").status(isValid).build();} catch (SQLException e) {return HealthCheckResponse.named("Database connection health check").down().withData("error", e.getMessage()).build();}}
}
10.2 指标监控
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
@Path("/metrics-demo")
public class MetricsResource {@InjectMeterRegistry meterRegistry;private final Counter requestCounter;private final Timer responseTimer;public MetricsResource(MeterRegistry meterRegistry) {this.meterRegistry = meterRegistry;this.requestCounter = Counter.builder("api_requests_total").description("Total number of API requests").register(meterRegistry);this.responseTimer = Timer.builder("api_response_time").description("API response time").register(meterRegistry);}@GET@Timed(name = "api_timer", description = "API call timer")@Counted(name = "api_counter", description = "API call counter")public String getMetrics() {return Timer.Sample.start(meterRegistry).stop(responseTimer).toString();}
}
10.3 缓存
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-cache</artifactId>
</dependency>
@ApplicationScoped
public class CachedService {@CacheResult(cacheName = "user-cache")public User getUser(String userId) {// 模拟耗时操作return userRepository.findById(userId);}@CacheInvalidate(cacheName = "user-cache")public void updateUser(String userId, User user) {userRepository.update(userId, user);}@CacheInvalidateAll(cacheName = "user-cache")public void clearUserCache() {// 清空缓存}
}
10.4 消息队列
<dependency><groupId>io.quarkus</groupId><artifactId>quarkus-smallrye-reactive-messaging-rabbitmq</artifactId>
</dependency>
@ApplicationScoped
public class MessageProcessor {@Incoming("input-channel")@Outgoing("output-channel")public String processMessage(String message) {return "Processed: " + message.toUpperCase();}@Incoming("notifications")public void handleNotification(String notification) {System.out.println("Received notification: " + notification);}
}
# 消息队列配置
mp.messaging.incoming.input-channel.connector=smallrye-rabbitmq
mp.messaging.incoming.input-channel.queue.name=input-queuemp.messaging.outgoing.output-channel.connector=smallrye-rabbitmq
mp.messaging.outgoing.output-channel.exchange.name=output-exchange
11. 性能优化
11.1 GraalVM原生镜像优化
# 原生编译优化配置
quarkus.native.additional-build-args=-H:+ReportExceptionStackTraces,--initialize-at-run-time=org.postgresql.sspi.SSPIClient
quarkus.native.enable-https-url-handler=true
quarkus.native.enable-all-security-services=true
11.2 JVM优化
# JVM启动参数优化
java -XX:+UseG1GC \-XX:MaxGCPauseMillis=100 \-Xms256m \-Xmx512m \-jar target/quarkus-app/quarkus-run.jar
11.3 连接池优化
# 数据库连接池配置
quarkus.datasource.jdbc.min-size=5
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.acquisition-timeout=PT30S
12. 开发工具和技巧
12.1 开发模式特性
# 启动开发模式
mvn quarkus:dev# 开发模式特性:
# - 热重载
# - 实时编码
# - Dev UI: http://localhost:8080/q/dev/
# - 自动测试运行
12.2 配置热重载
# 支持配置文件热重载
quarkus.live-reload.instrumentation=true
12.3 调试配置
# 启用调试模式
mvn quarkus:dev -Ddebug=5005# 或者
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar target/quarkus-app/quarkus-run.jar
13. 最佳实践
13.1 项目结构最佳实践
src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── config/ # 配置类
│ │ ├── entity/ # 实体类
│ │ ├── repository/ # 数据访问层
│ │ ├── service/ # 业务逻辑层
│ │ ├── resource/ # REST资源层
│ │ └── dto/ # 数据传输对象
│ └── resources/
│ ├── application.properties
│ ├── application-dev.properties
│ ├── application-prod.properties
│ └── META-INF/
└── test/
13.2 异常处理
@Provider
public class GlobalExceptionHandler implements ExceptionMapper<Exception> {@Overridepublic Response toResponse(Exception exception) {ErrorResponse error = new ErrorResponse();error.message = "Internal server error";error.timestamp = LocalDateTime.now();if (exception instanceof WebApplicationException) {WebApplicationException webEx = (WebApplicationException) exception;error.message = webEx.getMessage();return Response.status(webEx.getResponse().getStatus()).entity(error).build();}return Response.status(500).entity(error).build();}
}
13.3 日志配置
# 日志级别配置
quarkus.log.level=INFO
quarkus.log.category."com.example".level=DEBUG
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n# 日志文件配置
quarkus.log.file.enable=true
quarkus.log.file.path=logs/application.log
quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n
14. 生产环境部署
14.1 环境配置
# application-prod.properties
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://prod-db:5432/myapp
%prod.quarkus.log.level=WARN
%prod.quarkus.hibernate-orm.database.generation=validate
%prod.quarkus.http.port=8080
%prod.quarkus.http.host=0.0.0.0
14.2 Kubernetes部署
# kubernetes-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: quarkus-app
spec:replicas: 3selector:matchLabels:app: quarkus-apptemplate:metadata:labels:app: quarkus-appspec:containers:- name: quarkus-appimage: my-app:latestports:- containerPort: 8080env:- name: QUARKUS_PROFILEvalue: "prod"resources:requests:memory: "128Mi"cpu: "100m"limits:memory: "256Mi"cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:name: quarkus-app-service
spec:selector:app: quarkus-appports:- port: 80targetPort: 8080type: LoadBalancer
总结
Quarkus是一个现代化的Java框架,特别适合云原生和微服务架构。通过本指南,你已经学习了:
- 基础概念:项目创建、配置管理、依赖注入
- 数据库集成:Hibernate ORM Panache、反应式数据库
- REST API开发:传统和反应式REST服务
- 安全性:认证授权、JWT集成
- 测试策略:单元测试、集成测试
- 部署方案:JVM模式、原生编译、容器化
- 高级特性:监控、缓存、消息队列
- 性能优化:GraalVM、JVM调优
- 生产部署:Kubernetes、环境配置
继续学习Quarkus的建议:
- 深入学习GraalVM原生编译
- 探索更多Quarkus扩展
- 实践微服务架构模式
- 学习云原生部署和运维
这将帮助你成为Quarkus专家,构建高性能的现代Java应用!