Add aot-cache module: the JDK 25 AOT cache on Spring Boot 4.1 vs AppCDS, Spring AOT and GraalVM native
A Spring Boot 4.1.1 order service started 12 ways (plain and extracted jar, Spring AOT output, AppCDS, AOT cache trained with and without traffic, JDK 27, native image), ten interleaved rounds each, with first-request latency; 24 cache-mismatch cases; Docker layer arithmetic. Transcripts are in output/ (no docs/ folder). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.ankurm.aotcache;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AotCacheApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AotCacheApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ankurm.aotcache;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
/** The request body of POST /orders. Bean Validation and Jackson both have to work on it. */
|
||||
public record NewOrder(
|
||||
@NotBlank @Email String customer,
|
||||
@NotBlank @Pattern(regexp = "[A-Z]{3}-[0-9]{4}") String sku,
|
||||
@Min(1) @Max(1000) int quantity) {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ankurm.aotcache;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/** A stored order. */
|
||||
public record Order(long id, String customer, String sku, int quantity, BigDecimal total, Instant createdAt) {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ankurm.aotcache;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class OrderController {
|
||||
|
||||
private final OrderService service;
|
||||
|
||||
public OrderController(OrderService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping("/ping")
|
||||
public String ping() {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/orders")
|
||||
public ResponseEntity<Order> create(@Valid @RequestBody NewOrder body) {
|
||||
Order o = service.create(body);
|
||||
return ResponseEntity.created(URI.create("/orders/" + o.id())).body(o);
|
||||
}
|
||||
|
||||
@GetMapping("/orders/{id}")
|
||||
public ResponseEntity<Order> get(@PathVariable long id) {
|
||||
return service.find(id).map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.ankurm.aotcache;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OrderService {
|
||||
|
||||
private final AtomicLong ids = new AtomicLong();
|
||||
private final Map<Long, Order> orders = new ConcurrentHashMap<>();
|
||||
|
||||
public Order create(NewOrder in) {
|
||||
long id = ids.incrementAndGet();
|
||||
BigDecimal unit = BigDecimal.valueOf(4_99, 2);
|
||||
Order o = new Order(id, in.customer(), in.sku(), in.quantity(), unit.multiply(BigDecimal.valueOf(in.quantity())), Instant.now());
|
||||
orders.put(id, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
public Optional<Order> find(long id) {
|
||||
return Optional.ofNullable(orders.get(id));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user