Разработка бэкенда сайта на Java (Quarkus)
Quarkus — Java-фреймворк, переосмысленный для cloud-native и Kubernetes. Главное отличие от Spring Boot: Quarkus компилирует приложение в нативный бинарник через GraalVM Native Image. Время холодного старта — 0.01–0.1 секунды против 2–10 секунд у Spring Boot. Потребление памяти — 20–60 МБ против 200–500 МБ.
Это не просто цифры для бенчмарков. В Kubernetes-окружении с автоскейлингом быстрый старт означает реальное горизонтальное масштабирование: Pod поднимается за секунды, не минуты. На Serverless — это разница между рабочим и нерабочим решением.
В JVM-режиме Quarkus конкурирует с Spring Boot, в нативном — с Go.
Отличия от Spring Boot
Quarkus использует знакомые спецификации: JAX-RS, CDI, JPA, MicroProfile. Если знаете Spring, переход занимает несколько дней. Ключевые отличия:
- Dependency Injection через CDI (
@ApplicationScoped,@RequestScoped), не Spring DI - REST через RESTEasy Reactive (JAX-RS), не Spring MVC
- ORM — Hibernate с Panache (Active Record или Repository pattern)
- Конфигурация через
application.propertiesили YAML, MicroProfile Config
Структура и REST
// Product entity с Panache Active Record
@Entity
@Table(name = "products")
public class Product extends PanacheEntityBase {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
@Column(nullable = false, length = 255)
public String name;
@Column(unique = true)
public String slug;
@Column(precision = 10, scale = 2)
public BigDecimal price;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
public Category category;
public boolean isActive = true;
@Column(columnDefinition = "jsonb")
@Type(JsonType.class)
public Map<String, Object> attributes = new HashMap<>();
// Статические методы Panache
public static List<Product> findActive() {
return list("isActive", true);
}
public static Page<Product> findActiveByCategory(Long categoryId, int page, int size) {
return find("category.id = ?1 and isActive = true", categoryId)
.page(page, size);
}
}
Resource (Controller)
@Path("/api/v1/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ApplicationScoped
public class ProductResource {
@Inject
ProductService productService;
@GET
@Authenticated
public Response list(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") @Max(100) int size,
@QueryParam("category_id") Long categoryId) {
PanacheQuery<Product> query = categoryId != null
? Product.find("category.id = ?1 and isActive = true", categoryId)
: Product.find("isActive", true);
List<Product> products = query
.page(page, size)
.list();
long total = query.count();
return Response.ok(new PagedResponse<>(
products.stream().map(ProductDto::from).toList(),
page, size, total
)).build();
}
@POST
@RolesAllowed("admin")
@Transactional
public Response create(@Valid CreateProductRequest request) {
Product product = productService.create(request);
return Response.status(Response.Status.CREATED)
.entity(ProductDto.from(product))
.build();
}
@GET
@Path("/{id}")
public ProductDto get(@PathParam("id") Long id) {
return Product.findByIdOptional(id)
.map(ProductDto::from)
.orElseThrow(NotFoundException::new);
}
@DELETE
@Path("/{id}")
@RolesAllowed("admin")
@Transactional
public Response delete(@PathParam("id") Long id) {
boolean deleted = Product.deleteById(id);
return deleted ? Response.noContent().build() : Response.status(404).build();
}
}
Reactive endpoint
Quarkus с RESTEasy Reactive поддерживает неблокирующие операции нативно:
@GET
@Path("/search")
public Uni<List<ProductDto>> search(@QueryParam("q") String query) {
return Product.<Product>find("name like ?1", "%" + query + "%")
.list()
.map(products -> products.stream().map(ProductDto::from).toList());
}
// Реактивная работа с БД через Hibernate Reactive
@GET
@Path("/{id}/with-reviews")
public Uni<ProductWithReviews> getWithReviews(@PathParam("id") Long id) {
return Panache.withTransaction(() ->
Product.<Product>findById(id)
.flatMap(product -> Review.<Review>find("product.id", id).list()
.map(reviews -> new ProductWithReviews(product, reviews)))
);
}
Security через SmallRye JWT
# application.properties
mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem
mp.jwt.verify.issuer=https://myapp.com
quarkus.http.auth.permission.authenticated.paths=/api/v1/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/v1/auth/*,/api/v1/products
quarkus.http.auth.permission.public.policy=permit
@Path("/api/v1/auth")
public class AuthResource {
@Inject
@Claim(standard = Claims.sub)
Optional<JsonString> subject;
@POST
@Path("/login")
@PermitAll
public Response login(@Valid LoginRequest request) {
User user = User.findByEmail(request.email())
.orElseThrow(() -> new UnauthorizedException("Invalid credentials"));
if (!BCrypt.verifyer().verify(request.password().toCharArray(), user.passwordHash).verified) {
throw new UnauthorizedException("Invalid credentials");
}
String token = Jwt.issuer("https://myapp.com")
.subject(user.id.toString())
.groups(Set.of(user.role))
.claim("email", user.email)
.expiresIn(Duration.ofHours(1))
.sign();
return Response.ok(new LoginResponse(token)).build();
}
}
Native build
# JVM mode (обычная сборка)
./mvnw package -DskipTests
java -jar target/quarkus-app/quarkus-run.jar
# Native image — требует GraalVM или Docker
./mvnw package -Pnative -DskipTests
# Native в Docker без локального GraalVM
./mvnw package -Pnative -Dquarkus.native.container-build=true
docker build -f src/main/docker/Dockerfile.native -t myapp .
# Размер образа: ~100MB (vs ~500MB JVM Spring Boot)
# Startup: ~50ms (vs 3-8s Spring Boot)
# Memory: ~30MB (vs ~200MB Spring Boot)
Kafka интеграция
// Продюсер
@ApplicationScoped
public class ProductEventProducer {
@Inject
@Channel("products-out")
Emitter<ProductEvent> emitter;
public void publishCreated(Product product) {
emitter.send(Message.of(new ProductEvent("created", product.id, product.name)));
}
}
// Консьюмер
@ApplicationScoped
public class InventoryConsumer {
@Incoming("inventory-updates")
public void onInventoryUpdate(InventoryUpdateEvent event) {
Product.update("stock = ?1 where id = ?2", event.stock(), event.productId());
}
}
Dev mode
Quarkus Dev Mode — один из лучших hot-reload механизмов в Java-экосистеме:
./mvnw quarkus:dev
# Любые изменения применяются без перезапуска
# Dev UI доступен на localhost:8080/q/dev
# Встроенный Dev Services: PostgreSQL, Redis, Kafka — запускаются автоматически в Docker
Сроки разработки
- Настройка проекта + Dev Services + миграции Flyway — 3–5 дней
- Entities (Panache) + Resources — 1–1,5 недели
- Security + JWT — 3–5 дней
- Reactive endpoints если нужны — дополнительная неделя
- Native build настройка — 2–5 дней (часто требует reflection hints)
- Тесты (QuarkusTest + RestAssured) — 1 неделя
Корпоративный бэкенд: 7–14 недель. Quarkus окупается в Kubernetes-среде, особенно когда нужен быстрый автоскейлинг или Serverless-деплой.







