Cette page décrit ce qui se passe entre mvn package et le premier 200 OK. Elle suit le code à travers vidocq-runtime-maven-plugin, vidocq-runtime-core et la SPI, et détaille la grammaire d’extensions.

Vue d’ensemble — du code source au runtime

Diagram

Diagramme de séquence — boot

Diagram

Les phases 4 et 5 s’exécutent dans des virtual threads distincts via StructuredTaskScope, ce qui permet à Cassini d’enregistrer ses routes pendant que Mansart valide la connexion à la base.

Mécanisme d’extensions

SPI publique

Le module vidocq-runtime-spi expose les interfaces de contribution. Les classes principales aujourd’hui livrées :

Type Rôle

io.vidocq.runtime.spi.VidocqExtension

Interface marqueur déclarée via ServiceLoader ou META-INF/services. Une extension implémente configure(ExtensionContext) pour s’enregistrer.

io.vidocq.runtime.spi.ExtensionContext

API de contribution — accès au registre de BuildItem, à la config, à la phase courante.

io.vidocq.runtime.spi.VidocqConfiguration

Interface lue au build pour résoudre les options de l’extension.

io.vidocq.runtime.spi.config.VidocqConfig

Façade MicroProfile Config ré-exposée, avec Converter<T> et ConfigSource.

Source : vidocq-runtime-spi/src/main/java/io/vidocq/runtime/spi/.

APT processor

Le vidocq-runtime-processor (dérivé du vauban-processor) scanne les classes annotées @BuildStep, @Recorder, @Path, @ApplicationScoped, etc. Il produit :

  • un index META-INF/vidocq/extensions.list (une ligne par classe d’extension) ;

  • un index META-INF/vauban/beans.list (réutilisé par Vauban) ;

  • le fichier d’options de configuration consommé par les recorders.

Aucune réflexion runtime — l’index est lu au démarrage par un simple getResourceAsStream.

Génération Class-File API

Quand un build step appelle une méthode sur un @Recorder, le moteur n’exécute pas l’appel : il l’enregistre. À la fin du graphe, vidocq-runtime-core synthétise une classe RuntimeBootstrap via la Class-File API (JEP 484). Cette classe contient une suite d'`invokevirtual` qui, rejouée au démarrage, reproduit l’effet désiré sans aucune réflexion.

Concrètement :

@Recorder
public class HttpRecorder {
    public RuntimeValue<Server> startServer(int port) { ... }
}

@BuildStep
@Record(RUNTIME_INIT)
public ServerStartedBuildItem boot(HttpRecorder rec, HttpConfig cfg) {
    rec.startServer(cfg.port());                  // <-- enregistré
    return new ServerStartedBuildItem();
}

À la compilation, vidocq-runtime-core émet :

// classe générée — pseudo-code
class RuntimeBootstrap_HttpRecorder {
    static void __runtimeInit() {
        new HttpRecorder().startServer(8080);     // <-- rejoué
    }
}

Modèle de threading

  • Bootstrap — un seul thread plateforme, pas de pool. Le boot est volontairement séquentiel pour faciliter le diagnostic.

  • I/O HTTPExecutors.newVirtualThreadPerTaskExecutor() côté Chappe. Une connexion = un virtual thread. Pas de réacteur, pas de callback.

  • Persistence — pool JDBC Mansart avec Semaphore non-équitable. ScopedValue<Connection> propage la connexion courante dans une transaction sans ThreadLocal.

  • Health checks périodiques — virtual threads schédulés via StructuredTaskScope.

Aucun pool de threads plateforme n’est créé par défaut. La règle est documentée dans le CLAUDE.md racine du workspace.

Lecture conseillée

  • Code source : vidocq-runtime-core/src/main/java/io/vidocq/runtime/core/ (boot orchestrator)

  • SPI : vidocq-runtime-spi/src/main/java/io/vidocq/runtime/spi/

  • Plugin Maven : vidocq-runtime-maven-plugin/

  • Exemples : vidocq-runtime-examples/vidocq-runtime-cassini-rest-example/, vidocq-runtime-mansart-h2-example/

Pour aller plus loin