Codebeispiele folgen in einer späteren Revision.
Auf dieser Seite
Behandelte Architektureigenschaften
- P-1Eine versiegelte Hierarchie, die Vorschläge von verifizierten Werten trennt, Validierung an der Web-Grenze und Modulregeln, die der Build verifiziert.
- P-4Micrometer Observation und Tracing für den Ausführungskontext, die Audit-Identität in jedem Vertrag und Audit-Einträge, die innerhalb der fachlichen Transaktion geschrieben werden.
- P-5Herkunft als Felder der Werttypen, explizit serialisiert.
- P-6Architekturverifikation in der Testphase und Pflicht-Checks, die nicht dadurch bestehen können, dass sie übersprungen werden.
- P-7Ports im Domänenmodul und Adapter in eigenen Modulen.
- P-8Eine Policy-Schnittstelle mit einem Engine-Adapter und Entscheidungen, die mit ihrer Revision festgehalten werden.
- P-2, P-3Nur in der Tiefe, in der COADF sie veröffentlicht.
Architektonische Absicht
Springs Stärke für diese Eigenschaften ist die Deklaration: Constraints an Typen, Transaktionen und Validierung, die der Container anwendet, Observations, die einmal konfiguriert werden, Modulregeln, die ein Test prüft. Sein typisches Versagen ist die Kehrseite desselben Designs. Eine Deklaration gilt auf den Pfaden, die der Container abfängt, über einen Proxy, an einem Web-Binding oder auf einem Executor, den er konfiguriert hat, und nirgendwo sonst. Eine als Annotation geschriebene Eigenschaft ist nur so stark wie die Menge der Aufrufe, die tatsächlich durch Spring laufen.
Dieses Profil bildet jede Eigenschaft auf Spring Boot 4 und Spring Framework 7 ab, die zum Zeitpunkt des Schreibens aktuelle Generation, und benennt die Stellen, an denen eine deklarierte Eigenschaft stillschweigend nicht mehr gilt.
Technologiezuordnung
| Architektureigenschaft | Java und Spring |
|---|---|
| Grenztyp | Ein sealed Interface mit record-Implementierungen: ein Vorschlagstyp und ein verifizierter Typ, in verschiedenen Modulen konstruiert. Records sind flach unveränderliche Datenträger: Eine Komponente, die eine veränderliche Liste ist, bleibt veränderlich, deshalb im Konstruktor kopieren. Sealed Classes sind seit Java 17 ein Standardfeature. |
| Laufzeitvalidierung | Jakarta-Validation-Constraints an Request-Typen, ausgelöst mit @Valid. Eine fehlgeschlagene @RequestBody-Validierung löst MethodArgumentNotValidException aus, standardmäßig mit 400 beantwortet. |
| Unbekannte Felder | Eine explizite, getestete Entscheidung an Grenztypen über Properties, die der Typ nicht deklariert, statt der jeweils aktuellen Konfiguration des JSON-Mappers. |
| Architekturregel | ApplicationModules.verify() von Spring Modulith oder ArchUnit-Regeln, als Unit-Tests geschrieben. |
| Ausführungskontext | Micrometer Observation und Micrometer Tracing, an OpenTelemetry angebunden. |
| Asynchroner Kontext | ContextPropagatingTaskDecorator mit der Micrometer-Bibliothek context-propagation; für den automatisch konfigurierten Executor die Boot-Property spring.task.execution.propagate-context. |
| Prüfspur | Einträge, die in der fachlichen Transaktion geschrieben werden; Datenbank-Grants und Trigger wie im PostgreSQL-Beispiel; die Event Publication Registry von Spring Modulith für Events, die nicht verloren gehen dürfen. |
| Isolierung von Standards | Port-Interfaces im Domänenmodul; ein Adaptermodul pro externem System; der Client des Anbieters für die Domäne nie sichtbar. |
| Policy | Eine Policy-Schnittstelle, die der Domäne gehört, mit einem Adapter für Open Policy Agent, oder Regeltabellen; die Revision an der Entscheidung gespeichert. |
| Integrationstests | Ein echtes PostgreSQL über Testcontainers, angebunden mit @ServiceConnection. |
Referenzmuster
Codebeispiele folgen in einer späteren Revision. Sie werden zurückgestellt, bis eine prüfende Person aus diesem Ökosystem sie gelesen hat, statt geschrieben zu werden, damit die vier Profile gleich aussehen. Die folgende Struktur ist das Referenzmuster, das diese Beispiele umsetzen werden.
Module
inferenceruft das Modell auf und gibt einProposalzurück, ein Record, das den Wert, die Methode und die Herkunft trägt. Es hat keine Abhängigkeit vonrecordsoderaudit, und eine Modulith-Verifikation oder eine ArchUnit-Regel hält das in einem Test fest.recordsist das einzige Modul, das einenVerifiedValueerzeugen kann. Der Typ ist außerhalb des Moduls nicht öffentlich, oder er ist eine Klasse, deren Konstruktor es nicht ist: Ein öffentliches Record kann seinen Konstruktor nicht verbergen, denn der kanonische Konstruktor eines öffentlichen Records muss selbst öffentlich sein. Die Erzeugung läuft über eine Factory, die die Verifikation durch eine namentlich benannte Person verlangt.audithängt Einträge mit den veröffentlichten Feldern an, innerhalb der Transaktion der Änderung, die sie festhalten, über ein Repository, das weder Update noch Delete anbietet.classificationdeklariert den Port;classification.vendorimplementiert ihn und ist das einzige Modul, das den Client des Anbieters oder dessen Typen sehen kann.policydeklariert die Policy-Schnittstelle und den Entscheidungsdatensatz; ein Adaptermodul spricht mit der Engine.
Grenzen zur Laufzeit
Validiert wird am Web-Binding, wo Spring Constraints am Request-Body auswertet, und noch einmal in der Domänen-Factory, denn das Web-Binding ist ein Einstiegspunkt unter mehreren: Ein Message-Listener, ein Batch-Job und ein Test erreichen die Domäne alle, ohne es zu passieren.
Observations umschließen die Grenze und die externen Aufrufe. Jeder Executor, der Arbeit für eine Anfrage ausführt, ist so konfiguriert, dass er den Kontext weitergibt, und die Audit-Identität ist ein Feld jeder Nachricht und jedes Job-Arguments, nie nachträglich aus einem Thread-Local zurückgewonnen.
Fehlermuster
Selbstaufruf umgeht den Proxy
Spring AOP basiert auf Proxies: Ein Aufruf von einer Methode einer Bean an eine andere Methode derselben Bean läuft nicht durch den Proxy, deshalb gelten Methodenvalidierung und
@Transactionalfür ihn nicht. Ein Constraint, der für Aufrufer außerhalb der Bean gilt, gilt nicht für die Bean selbst, und dort beginnt oft der Batch-Pfad.Constraints deklariert, nie ausgewertet
Jakarta-Validation-Constraints an einem Typ bewirken für sich allein nichts. Ausgewertet werden sie dort, wo etwas die Validierung auslöst:
@Validoder@Validatedan einem Web-Binding oder Methodenvalidierung über den Proxy. Ein Message-Listener, der denselben Typ empfängt, validiert nichts, solange er es nicht anfordert.Nicht deklarierte Properties der Mapper-Konfiguration überlassen
Ob ein eingehendes JSON-Dokument Properties tragen darf, die der Typ nicht deklariert, ist eine Einstellung des JSON-Mappers. Für einen Grenztyp ist die richtige Antwort meist, sie abzulehnen, und diese Entscheidung gehört an den Typ und in einen Test, nicht in eine Anwendungs-Property, die jemand anderes ändern kann.
Kontext verloren bei
@Asyncund eigenen ExecutorsUm den Observation-Kontext an andere Threads weiterzugeben, braucht es einen
ContextPropagatingTaskDecoratorund die Bibliothek context-propagation; für den automatisch konfigurierten Executor macht Spring Boot das überspring.task.execution.propagate-contextzu einer Opt-in-Einstellung, die standardmäßig aus ist. An einen Thread-Pool übergebene Arbeit läuft dann ohne ihren Trace.ORM-Unveränderlichkeit für eine Audit-Absicherung gehalten
Hibernate ignoriert Änderungen im Speicher an einer verwalteten
@Immutable-Entität, ohne Update und ohne Exception. Bulk-Updates dagegen werfen in Hibernate 7 standardmäßig eine Exception und erzeugten in 6.6 nur eine Warnung. Nichts davon hält einen zweiten Client, ein Skript oder eine Migration davon ab, die Tabelle zu ändern; der Schutz gehört in die Datenbank.Audit-Events nach dem Commit verloren
Ein Event, das nach dem Commit der Transaktion behandelt wird, geht verloren, wenn der Handler fehlschlägt, es sei denn, etwas hat es festgehalten. Die Event Publication Registry von Spring Modulith schreibt einen Eintrag in der veröffentlichenden Transaktion und bewahrt fehlgeschlagene Veröffentlichungen für eine erneute Übermittlung auf; sie beim Neustart automatisch erneut zu veröffentlichen, ist eine Einstellung, die eigens eingeschaltet werden muss.
Ein öffentliches Record als verifizierter Typ
Der kanonische Konstruktor eines öffentlichen Records muss öffentlich sein, also kann jeder Code, der den Typ sieht, einen verifizierten Wert ohne Verifikation bauen. Den Typ außer Reichweite halten oder eine Klasse mit privatem Konstruktor und einer Factory verwenden.
Zwei Tracing-Bridges
Micrometer Tracing bindet an Brave oder an OpenTelemetry an, und seine Dokumentation verlangt, nur eines davon zu wählen. Zwei auf dem Classpath erzeugen Traces, die davon abhängen, welche sich durchsetzt.
Integrationstests gegen eine andere Datenbank
Grants, Trigger und das Verhalten von Constraints sind Eigenschaften der echten Datenbank. Tests gegen einen eingebetteten Ersatz verifizieren den Code und nicht die Eigenschaft.
Verifikation
Unit-Test
Bestanden, wenn: Der verifizierte Typ lässt sich nur über die Factory erzeugen, und nur mit einer Verifikation durch eine namentlich benannte Person; eine Ablehnung lässt das Attribut leer.
Zahnbeweis: Den verifizierten Typ in einem Wegwerf-Branch öffentlich machen: Ein Test, der prüft, dass er aus dem Inferenzmodul nicht zugänglich ist, schlägt fehl.
Architekturtest
Bestanden, wenn: Die Verifikation von Spring Modulith besteht, oder die ArchUnit-Regeln bestehen: keine Abhängigkeit von
inferencezurecordsoderaudit, kein Anbietertyp in der Domäne. ArchUnit prüft Abhängigkeiten zwischen Paketen und Klassen als gewöhnliche Unit-Tests, und die Verifikation von Modulith lehnt Zyklen zwischen Modulen und Verweise in die internen Pakete eines anderen Moduls ab, außer in Module, die als offen deklariert sind. Beide Werkzeuge prüfen die aufgeschriebenen Regeln; ob es die richtigen Regeln sind, ist Designsache des Teams.Zahnbeweis: Die verbotene Abhängigkeit einbauen: Die Verifikation schlägt fehl.
Integrationstest
Bestanden, wenn: Gegen PostgreSQL aus Testcontainers: Die Rolle der Anwendung kann die Prüfspur weder ändern noch löschen, und Einträge werden in derselben Transaktion wie die Änderung geschrieben.
Zahnbeweis: Die fachliche Transaktion nach dem Schreiben zurückrollen: Der Audit-Eintrag darf das nicht überstehen.
Integrationstest
Bestanden, wenn: Der Kontext übersteht die Executors, die die Anwendung verwendet: Ein In-Memory-Exporter zeigt die asynchrone Arbeit als Teil desselben Traces, und die Audit-Identität steht in ihrem Datensatz.
Zahnbeweis: Den Task-Decorator entfernen: Der Test schlägt fehl.
Vertragstest
Bestanden, wenn: Produzent und Konsument stimmen bei den Verträgen für Vorschlag und Entscheidung überein, mit der Herkunft und der Revision als Pflichtfeldern.
End-to-End-Test
Bestanden, wenn: Eine Ausgabe, deren Attribut nicht verifiziert wurde, kann nicht veröffentlicht werden, gleich über welchen Einstiegspunkt die Anfrage kam.
Alternative Umsetzungen
- Andere Java-Frameworks (Quarkus, Micronaut, Jakarta EE) drücken dieselbe Grenze mit anderen Interception-Modellen aus; die Frage nach dem Selbstaufruf muss an jedes gestellt werden.
- Explizites SQL (jOOQ oder reines JDBC) für die Prüfspur statt eines ORM, wo die genauen Statements wichtiger sind als der Komfort des Mappings.
- Event-Sourcing-Frameworks, wo die Historie das Modell ist.
- Regeltabellen, die der Anwendung gehören, statt einer externen Policy-Engine, mit derselben Anforderung an die Revision.
Abwägungen
- Deklarativ ist knapp und unsichtbar. An der Aufrufstelle ist nicht zu erkennen, ob ein Constraint oder eine Transaktion gilt; das müssen Tests zeigen.
- Spring Modulith kodiert Konventionen, was schnell einzuführen und meinungsstark ist; ArchUnit ist allgemein und verlangt, die Regeln auszuschreiben.
- JPA ist bequem und legt eine Schicht zwischen den Code und die eigenen Schutzmechanismen der Datenbank. Für die Prüfspur ist diese Schicht genau das, was durchschaut werden muss.
- Modulgrenzen innerhalb einer deploybaren Einheit halten das Betriebsmodell einfach und machen die Grenze vollständig von der Verifikation im Build abhängig.
Grenzen
- Für dieses Profil wird in Companion 1.0 kein Code veröffentlicht, und kein Beispiel wurde ausgeführt. Das beschriebene Verhalten stammt aus der aktuellen Dokumentation der Hersteller, eingesehen am 11. September 2026, für Spring Boot 4.1, Spring Framework 7.0, Spring Modulith 2.1, Hibernate ORM 7.4 und Java SE 25.
- Nichts hier zeigt, wie Konfidenz dargestellt wird, wann eine Prüfung erforderlich ist oder wie die Prüfung organisiert ist; diese Teile von P-2 und P-3 veröffentlicht COADF nicht.
- Alles Zitierte ist Verhalten der Sprache oder des Frameworks. Die Architektureigenschaft, dass ein Vorschlag ohne Verifikation nicht zu einem Datensatz werden kann, ist ein Design, das das Team noch entwerfen und testen muss: Keine Annotation, kein Record und keine Modulregel stellt sie von sich aus her.
Was dieses Profil nicht begründet
Wer diesem Profil folgt, begründet damit weder die Einhaltung regulatorischer Anforderungen noch eine Zertifizierung oder ein Verfahren zur Bewertung der Übereinstimmung mit Rechtsvorschriften, und Spring wird von COADF nicht vorausgesetzt.
Getestete Referenzumgebung
Für dieses Profil wurde kein Beispiel ausgeführt.
Quellen
- Oracle: java.lang.Record · Sprachdokumentation · Java SE 25 · Geprüft am 2026-09-11
- OpenJDK: JEP 409: Sealed Classes · Spezifikation · Geprüft am 2026-09-11
- Oracle: Java Language Specification: canonical constructors of record classes · Spezifikation · Java SE 25 · Geprüft am 2026-09-11
- Spring Framework: @RequestBody validation · offizielle Dokumentation · Spring Framework 7.0 · Geprüft am 2026-09-11
- Spring Framework: Understanding AOP proxies · offizielle Dokumentation · Spring Framework 7.0 · Geprüft am 2026-09-11
- Spring Framework: Spring-driven method validation · offizielle Dokumentation · Spring Framework 7.0 · Geprüft am 2026-09-11
- Spring Framework: Observability support: context propagation · offizielle Dokumentation · Spring Framework 7.0 · Geprüft am 2026-09-11
- Spring Boot: Observability: context propagation · offizielle Dokumentation · Spring Boot 4.1 · Geprüft am 2026-09-11
- Spring Boot: Tracing · offizielle Dokumentation · Spring Boot 4.1 · Geprüft am 2026-09-11
- Spring Boot: Testcontainers service connections · offizielle Dokumentation · Spring Boot 4.1 · Geprüft am 2026-09-11
- Spring Modulith: Verifying application module structure · offizielle Dokumentation · Spring Modulith 2.1 · Geprüft am 2026-09-11
- Spring Modulith: Event publication registry · offizielle Dokumentation · Spring Modulith 2.1 · Geprüft am 2026-09-11
- Hibernate ORM: Immutable entities · offizielle Dokumentation · Hibernate ORM 7.4 · Geprüft am 2026-09-11
- ArchUnit: ArchUnit user guide · offizielle Dokumentation · ArchUnit 1.5 · Geprüft am 2026-09-11
- Micrometer: Micrometer Tracing: supported tracers · offizielle Dokumentation · Micrometer Tracing 1.7 · Geprüft am 2026-09-11
