Mock Full 03 — Spring Professional (60 Fragen)
Prüfungsstil: Spring Professional Develop (2V0-72.22) — vollständiger 60-Fragen-Mock aus gemischten Themen.
Zeitlimit: ca. 130 Minuten (etwa 2 Minuten pro Frage).
Anleitung:
- Wähle pro Frage eine Option und nutze dann Antwort prüfen, um Erklärung und Punktestand zu sehen.
- Mit Zurück und Weiter durch das Set navigieren; deine Auswahl kannst du ändern, bis du prüfst.
- Bei jedem Fehler die Erklärung lesen und einen Merksatz notieren, bevor du weitermachst.
Themenverteilung:
- F1–10: Spring Core & DI
- F11–18: Konfiguration, Profile & Scopes
- F19–28: Spring Boot, Auto-Configuration & Actuator
- F29–36: Spring MVC, REST & Validierung
- F37–44: Datenzugriff, JPA & Transaktionen
- F45–50: Spring Security
- F51–56: Testing
- F57–60: AOP, Events, Async & Observability
Frage 1
Ein Legacy-Monolith wird auf Spring migriert. Das Team diskutiert, ob der Bootstrap mit BeanFactory oder ApplicationContext erfolgen soll.
Welche Fähigkeit ist in ApplicationContext verfügbar, aber NICHT im grundlegenden BeanFactory-Vertrag?
- A) Programmatisches Registrieren von Singleton- und Prototype-Bean-Definitionen
- B) Publizieren von Application-Events an registrierte Listener
- C) Auflösen von Bean-Abhängigkeiten über Konstruktor-Injection
- D) Nachschlagen von Beans per Name zur Laufzeit
Antwort & Erklärung
Richtige Antwort: B
ApplicationContext erweitert BeanFactory und fügt Enterprise-Features hinzu — etwa Event-Publikation, Internationalisierung, Resource-Loading-Muster und automatische BeanPostProcessor-Registrierung. BeanFactory unterstützt zentrale DI-Mechanismen inklusive Lookup und Dependency Resolution, publiziert aber keine ApplicationEvent-Objekte an ApplicationListener-Beans. In der Prüfung deuten „Enterprise-Features" fast immer auf Events, i18n oder AOP-Auto-Registrierung über den Context hin.
Warum die anderen Optionen falsch sind:
- BeanFactory kann Definitionen registrieren und Singleton-/Prototype-Scopes über BeanDefinition-APIs verwalten.
- Konstruktor-Injection ist ein zentrales IoC-Feature, das sowohl BeanFactory als auch ApplicationContext unterstützen.
- getBean()-Lookup ist grundlegendes BeanFactory-Verhalten, kein ApplicationContext-exklusives Feature.
Merksatz: „ApplicationContext = BeanFactory plus Events, i18n und reichere Lifecycle-Integration."
Weiterlernen: Buchkapitel
Frage 2
PaymentService hat zwei NotificationSender-Implementierungen auf dem Classpath: EmailNotificationSender und SmsNotificationSender.
Welcher Ansatz injiziert die SMS-Implementierung am saubersten in PaymentService, ohne Beans umzubenennen oder den E-Mail-Bean zu entfernen?
- A) SmsNotificationSender mit @Primary annotieren und NotificationSender ohne Qualifier injizieren
- B) Den PaymentService-Konstruktorparameter mit @Qualifier("smsNotificationSender") annotieren
- C) EmailNotificationSender mit @Lazy markieren, damit Spring den eager SMS-Bean bevorzugt
- D) @Resource auf dem Feld verwenden; Spring wählt immer den Bean, dessen Name dem Feldnamen entspricht
Antwort & Erklärung
Richtige Antwort: B
Wenn mehrere Beans denselben Typ implementieren, disambiguiert @Qualifier per Bean-Name (Standardname für @Component SmsNotificationSender ist smsNotificationSender). @Primary löst dasselbe Problem global, ändert aber die Standardauflösung für jeden Injection Point — das ist breiter als nötig. Konstruktor-Injection mit @Qualifier ist explizit, testfreundlich und eine häufige Prüfungsfalle gegenüber @Primary-Overuse.
Warum die anderen Optionen falsch sind:
- @Primary funktioniert, gilt aber context-weit; die Frage fragt nach der gezieltesten Wahl — @Qualifier am Injection Point.
- @Lazy verzögert nur die Initialisierung; es wählt nicht unter mehreren Kandidaten desselben Typs.
- @Resource nutzt namensbasiertes Lookup und garantiert keine Auswahl per Feldname, außer korrekt konfiguriert; es ist nicht „immer" SMS.
Merksatz: „Mehrere Implementierungen eines Typs: @Qualifier am Injection Point schlägt globales @Primary."
Weiterlernen: Buchkapitel
Frage 3
Angenommen, Component Scanning erfasst beide Klassen — wie viele Clock-Beans existieren und wie ist AuditTrail verdrahtet?
@Component
public class AuditTrail {
private final Clock clock;
public AuditTrail(Clock clock) { this.clock = clock; }
}
@Configuration
public class TimeConfig {
@Bean
public Clock systemClock() { return Clock.systemUTC(); }
}
- A) Ein Clock-Bean aus TimeConfig; Konstruktor-Injection befriedigt AuditTrail
- B) Zwei Clock-Beans; Startup schlägt fehl mit NoUniqueBeanDefinitionException
- C) Null Clock-Beans; AuditTrail wird mit clock = null erstellt
- D) Ein Clock-Bean wird implizit erzeugt, weil @Component-Klassen immer einen Clock bekommen
Antwort & Erklärung
Richtige Antwort: A
Eine @Bean-Methode in @Configuration registriert einen expliziten Singleton-Clock. AuditTrail deklariert eine Konstruktorabhängigkeit auf Clock; Spring autowired den einzigen passenden Bean. Kein impliziter Clock wird erzeugt, außer ein weiterer @Bean oder @Component implementiert oder stellt Clock bereit. Die Falle: zu glauben, @Component erzeuge Abhängigkeiten magisch.
Warum die anderen Optionen falsch sind:
- Ein zweiter Clock bräuchte einen weiteren @Bean oder eine Component, die Clock implementiert; nur systemClock() ist definiert.
- Spring setzt erforderliche Konstruktorabhängigkeiten nicht still auf null, wenn ein eindeutiger Bean existiert.
- @Component provisioniert keine Abhängigkeiten automatisch; es registriert nur AuditTrail selbst.
Merksatz: „Ein passender @Bean befriedigt Konstruktor-Injection für diesen Typ."
Weiterlernen: Buchkapitel
Frage 4
OrderFacade hängt von PricingService ab, der von DiscountPolicy abhängt, die wiederum OrderFacade für Tenant-Context braucht.
Die Anwendung schlägt beim Startup mit einem Circular-Dependency-Fehler fehl. Sowohl OrderFacade als auch PricingService nutzen Konstruktor-Injection. Was ist der Spring-empfohlene strukturelle Fix?
- A) spring.main.allow-circular-references=true in application.properties aktivieren
- B) @Lazy auf einem Konstruktorparameter hinzufügen, um den Zyklus bei der Erstellung zu brechen
- C) Alle drei Klassen auf Feld-Injection mit @Autowired umstellen
- D) Refactoring: gemeinsame Abhängigkeit extrahieren oder über Interface-Indirektion wie ObjectProvider oder event-getriebenes Lookup injizieren
Antwort & Erklärung
Richtige Antwort: D
Konstruktor-Injection-Zyklen sind ohne Redesign nicht befriedigbar, weil jeder Bean den anderen vollständig konstruiert braucht. @Lazy auf einem Konstruktorparameter kann einen Proxy-Edge-Case aufschieben, ist aber ein taktischer Workaround, kein empfohlener Design-Fix. Extraktion der gemeinsamen Sorge, ObjectProvider oder Entkopplung über Events beseitigt den strukturellen Zyklus. Feld-/Setter-Injection „funktioniert", versteckt aber Designprobleme und ist discouraged.
Warum die anderen Optionen falsch sind:
- allow-circular-references ist ein Boot-Escape-Hatch, nicht die empfohlene Design-Lösung in der Prüfung.
- @Lazy kann eine Abhängigkeit aufschieben, behebt aber nicht das bidirektionale Design; Prüfungsantworten bevorzugen strukturelle Entkopplung.
- Feld-Injection vermeidet den Konstruktor-Zyklus-Fehler, verletzt aber empfohlene Praxis und signalisiert schlechte Grenzen.
Merksatz: „Konstruktor-Zyklen brauchen Design-Entkopplung, keine versteckten Injection-Tricks."
Weiterlernen: Buchkapitel
Frage 5
Kein MetricsExporter-Bean ist im Context registriert. Was passiert, wenn ReportService erstellt und publish() aufgerufen wird?
@Service
public class ReportService {
@Autowired(required = false)
private MetricsExporter metricsExporter;
public void publish() {
if (metricsExporter != null) {
metricsExporter.flush();
}
}
}
- A) Context-Refresh schlägt fehl, weil @Autowired standardmäßig required=true ist
- B) ReportService wird erstellt; metricsExporter ist null; publish() läuft ohne flush()-Aufruf
- C) Spring erzeugt automatisch einen No-Op-MetricsExporter-Proxy
- D) ReportService-Bean wird komplett übersprungen und nie instanziiert
Antwort & Erklärung
Richtige Antwort: B
required=false macht Injection optional. Wenn kein Bean passt, injiziert Spring null für Objekttypen statt Startup-Fehler. Die publish()-Guard verhindert NullPointerException. Das Muster eignet sich für optionale Integrationen. Die Falle: Feld-@Autowired-Default (required=true) mit dem expliziten required=false hier zu verwechseln.
Warum die anderen Optionen falsch sind:
- required=false deaktiviert explizit das Fail-Fast-Verhalten bei fehlenden Beans.
- Spring fabriziert keine No-Op-Implementierungen für fehlende optionale Abhängigkeiten.
- Der Service bleibt ein verwalteter Bean; fehlende optionale Abhängigkeiten unterdrücken die Bean-Erstellung nicht.
Merksatz: „@Autowired(required=false) heißt: fehlender Bean wird null, kein Startup-Fehler."
Weiterlernen: Buchkapitel
Frage 6
Welche Aussage beschreibt Inversion of Control in Spring am besten?
- A) Entwickler rufen explizit Framework-Callbacks auf, um Objekte in main() zu erzeugen
- B) Der Container konstruiert Objekte, verdrahtet Abhängigkeiten und verwaltet den Lifecycle; Anwendungscode erhält fertige Collaborators
- C) Spring generiert Bytecode für jede Klasse, sodass Getter und Setter unnötig sind
- D) IoC gilt nur für @Controller-Klassen in der Web-Request-Verarbeitung
Antwort & Erklärung
Richtige Antwort: B
IoC bedeutet: Objekterzeugung und Dependency Wiring werden vom Container gesteuert, nicht vom Anwendungscode mit new und manuellen Setter-Ketten. Spring verwaltet Lifecycle-Callbacks, Scopes und Proxying wo konfiguriert. Es ist nicht auf Web-Controller beschränkt und eliminiert nicht die Notwendigkeit klarer Collaborator-Grenzen über Konstruktoren oder Methoden.
Warum die anderen Optionen falsch sind:
- IoC verlagert Erzeugung aus main/Anwendungscode; der Container treibt Instanziierung.
- Spring kann Proxies und Bytecode-Enhancement für AOP nutzen, aber IoC geht um Objekt-Assembly, nicht um Accessor-Eliminierung.
- IoC gilt für jeden Spring-verwalteten Bean, inklusive @Service, @Repository und @Configuration.
Merksatz: „IoC = Container baut und verdrahtet; dein Code konsumiert Collaborators."
Weiterlernen: Buchkapitel
Frage 7
Ohne @Qualifier — welcher CacheProvider wird in CatalogService injiziert?
public interface CacheProvider {}
@Component
@Primary
class RedisCacheProvider implements CacheProvider {}
@Component
class CaffeineCacheProvider implements CacheProvider {}
@Service
class CatalogService {
private final CacheProvider cache;
CatalogService(CacheProvider cache) { this.cache = cache; }
}
- A) CaffeineCacheProvider, weil er später im Component Scan erscheint
- B) Startup schlägt fehl, außer eine Implementierung wird vom Classpath entfernt
- C) Ein JDK-Dynamic-Proxy, der beide Provider zusammenführt
- D) RedisCacheProvider, weil er mit @Primary markiert ist
Antwort & Erklärung
Richtige Antwort: D
@Primary markiert einen bevorzugten Bean, wenn mehrere Kandidaten einen Injection Point matchen. RedisCacheProvider gewinnt ohne @Qualifier. Ohne @Primary würde Spring NoUniqueBeanDefinitionException werfen. Scan-Reihenfolge bestimmt keine Präferenz.
Warum die anderen Optionen falsch sind:
- Component-Scan-Reihenfolge ist kein Disambiguierungsmechanismus.
- Mehrere Beans sind gültig, wenn @Primary oder @Qualifier Mehrdeutigkeit auflöst.
- Spring merged mehrere konkrete Implementierungen nicht zu einem Proxy für plain Interface-Injection.
Merksatz: „@Primary bricht Gleichstand, wenn mehrere Beans denselben Typ matchen."
Weiterlernen: Buchkapitel
Frage 8
Ein Security-Team verlangt unveränderliche Service-Abhängigkeiten und klare Unit-Test-Konstruktion. Welchen Injection-Stil solltest du bevorzugen?
- A) Konstruktor-Injection mit finalen Feldern
- B) Feld-Injection mit @Autowired
- C) Setter-Injection für jede Abhängigkeit
- D) Lookup-Method-Injection für alle Collaborators
Antwort & Erklärung
Richtige Antwort: A
Konstruktor-Injection ermöglicht unveränderliche Felder (final), macht erforderliche Abhängigkeiten explizit und erlaubt plain new Service(mockDep)-Tests ohne Spring. Feld-Injection versteckt Abhängigkeiten und erschwert Tests. Setter-Injection passt zu optionalen Abhängigkeiten, nicht als Default für erforderliche Collaborators.
Warum die anderen Optionen falsch sind:
- Feld-Injection kann Unveränderlichkeit nicht erzwingen und ist schwerer isoliert zu testen.
- Setter-Injection ist für optionale oder rekonfigurierbare Abhängigkeiten, nicht als Default für erforderliches immutables Wiring.
- Lookup-Method-Injection löst Scoped-/Prototype-Delegationsprobleme, nicht allgemeines Service-Wiring.
Merksatz: „Bevorzuge Konstruktor-Injection für erforderliche, unveränderliche, testbare Abhängigkeiten."
Weiterlernen: Buchkapitel
Frage 9
Eine Klasse ist als @Component("billingGateway") im Package com.acme.payments deklariert. Wie lautet der Default-Bean-Name, wenn der explizite Name entfernt würde?
- A) com.acme.payments.BillingGateway
- B) billingGateway mit lower camel case abgeleitet vom Klassennamen BillingGateway
- C) BillingGateway mit exakter Klassenschreibweise
- D) payments.BillingGateway basierend auf Package-Suffix
Antwort & Erklärung
Richtige Antwort: B
Für @Component ohne expliziten value ist der Default-Bean-Name der dekapitalisierte einfache Klassenname: BillingGateway wird billingGateway. Vollqualifizierte Klassennamen sind keine Default-Bean-Namen. Explizites @Component("billingGateway") setzt den Namen direkt.
Warum die anderen Optionen falsch sind:
- Vollqualifizierte Namen sind nicht das Default-Namensschema für Stereotype-Annotationen.
- Default-Dekapitalisierung lowercaset nur das erste Zeichen; BillingGateway bleibt nicht as-is.
- Package-Suffixe werden nicht an Default-Bean-Namen angehängt.
Merksatz: „Default-@Component-Name = dekapitalisierter einfacher Klassenname."
Weiterlernen: Buchkapitel
Frage 10
Beans in com.acme.billing.core werden nicht entdeckt. Was ist der kleinste Fix?
@SpringBootApplication
public class BillingApp {
public static void main(String[] args) {
SpringApplication.run(BillingApp.class, args);
}
}
// Domain-Code liegt in com.acme.billing.core
// BillingApp liegt in com.acme.billing
- A) Jede Klasse aus core nach com.acme.billing verschieben
- B) @SpringBootApplication(scanBasePackages = "com.acme.billing") oder ein breiteres gemeinsames Root-Package hinzufügen
- C) @SpringBootApplication durch nur @EnableAutoConfiguration ersetzen
- D) @ComponentScan auf jeder einzelnen Bean-Klasse im core-Package hinzufügen
Antwort & Erklärung
Richtige Antwort: B
@SpringBootApplication komponiert @ComponentScan, das standardmäßig auf das Package der deklarierenden Klasse (com.acme.billing) und darunter scannt. Das Geschwister-Package com.acme.billing.core wird nicht gescannt. scanBasePackages auf ein Parent wie com.acme.billing (wenn unter gemeinsamer Root strukturiert) oder com.acme erweitern behebt Discovery ohne Klassen zu verschieben. @SpringBootApplication auf der Main-Klasse in einem Parent-Package ist das idiomatische Boot-Layout.
Warum die anderen Optionen falsch sind:
- Alle Klassen zu verschieben ist unnötig, wenn scanBasePackages den core-Package-Baum einschließen kann.
- @EnableAutoConfiguration allein aktiviert kein Component Scanning für @Service/@Component-Klassen.
- @ComponentScan pro Klasse ist noisy; eine zentrale Scan-Konfiguration ist bevorzugt.
Merksatz: „@SpringBootApplication scannt sein Package und Subpackages, außer scanBasePackages überschreibt."
Weiterlernen: Buchkapitel
Frage 11
In einer @Configuration-Klasse, die von vollständiger @Configuration-CGLIB-Enhancement verarbeitet wird — wie viele ObjectMapper-Instanzen stehen hinter den beiden @Bean-Methoden?
@Configuration
public class AppConfig {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper().findAndRegisterModules();
}
@Bean
public JsonWriter jsonWriter() {
return new JsonWriter(objectMapper());
}
}
- A) Zwei, weil jeder @Bean-Methodenaufruf eine frische Instanz erzeugt
- B) Null; @Bean-Methoden werden beim Context-Refresh nicht aufgerufen
- C) Eine; der abgefangene @Bean-Methodenaufruf liefert den Singleton aus dem Container
- D) Eine nur, wenn @Scope("prototype") zu objectMapper() hinzugefügt wird
Antwort & Erklärung
Richtige Antwort: C
In @Configuration-Klassen leiten @Bean-Methoden-Interceptions Aufrufe über den Container, sodass objectMapper() aus jsonWriter() den registrierten Singleton zurückgibt statt erneut new aufzurufen. Ohne @Configuration-Enhancement (plain @Bean in Nicht-Config-Klasse) würden direkte Aufrufe separate Instanzen erzeugen. Das ist eine klassische Zertifizierungsfalle.
Warum die anderen Optionen falsch sind:
- Doppelte Instanzen entstehen bei @Bean-Lite-Mode oder plain @Component-Klassen, nicht bei vollständiger @Configuration.
- @Bean-Methoden werden definitiv aufgerufen, um factory-produzierte Beans zu registrieren.
- Prototype-Scope würde mehrere ObjectMapper-Instanzen erzeugen; Default-Singleton-Scope teilt eine.
Merksatz: „@Configuration-@Bean-Methodenaufrufe sind proxied, um Container-verwaltete Singletons wiederzuverwenden."
Weiterlernen: Buchkapitel
Frage 12
Ein Multi-Modul-Billing-Service bindet Dutzende verschachtelte Tarif-Properties aus application.yml mit relaxed binding. Welcher Mechanismus ist am passendsten?
- A) @ConfigurationProperties auf einer typisierten Properties-Klasse, aktiviert via @EnableConfigurationProperties
- B) Einzelne @Value("${billing.tariff.peak.rate}")-Felder über Services verstreut
- C) Environment.getProperty()-manuelles Parsing nur in @PostConstruct-Methoden
- D) @PropertySource auf der Main-Klasse ohne Binding-Objekt
Antwort & Erklärung
Richtige Antwort: A
@ConfigurationProperties gruppiert hierarchische Konfiguration in einen validierten Typ, unterstützt relaxed binding (billing.tariff.peak-rate mappt auf peakRate) und hält Services frei von Property-Key-Strings. @Value ist okay für wenige Keys, skaliert aber schlecht für verschachtelte Strukturen. Manuelles Environment-Parsing dupliziert Framework-Funktionalität.
Warum die anderen Optionen falsch sind:
- @Value pro Feld wird bei verschachtelten Bäumen brüchig und verschleiert das Konfigurationsmodell.
- Environment allein fehlt strukturiertes Binding und Validierungsintegration im großen Maßstab.
- @PropertySource lädt eine Datei, bindet aber keine verschachtelten Strukturen ohne @ConfigurationProperties oder @Value.
Merksatz: „Große strukturierte Config-Bäume gehören in @ConfigurationProperties, nicht verstreute @Value."
Weiterlernen: Buchkapitel
Frage 13
Ein Bean ist mit @Profile("!prod") annotiert. In welcher Environment wird der Bean registriert?
- A) Nur wenn das prod-Profil aktiv ist
- B) Nie; negierte Profile sind in Spring ungültig
- C) Immer wenn die aktiven Profile prod NICHT enthalten
- D) Nur im Default-Profil ohne explizites spring.profiles.active
Antwort & Erklärung
Richtige Antwort: C
Profile-Ausdrücke unterstützen Negation. @Profile("!prod") registriert den Bean, wenn prod nicht unter den aktiven Profilen ist — inklusive dev, test oder mehreren anderen. Es ist nicht auf nur das Default-Profil beschränkt; jede Nicht-prod-Aktivierung qualifiziert.
Warum die anderen Optionen falsch sind:
- Das wäre @Profile("prod"), nicht die negierte Form.
- Negierte Profile sind gültige First-Class-Profile-Ausdrücke.
- Nicht-prod schließt explizite dev/test-Profile ein, nicht nur das implizite Default.
Merksatz: „@Profile("!prod") heißt: registrieren, wenn prod nicht aktiv ist."
Weiterlernen: Buchkapitel
Frage 14
CorrelationService ist ein Singleton. Wie viele unterschiedliche RequestIdGenerator-Instanzen hält er über die Anwendungslebensdauer?
@Component
@Scope("prototype")
class RequestIdGenerator {
private final String id = UUID.randomUUID().toString();
String getId() { return id; }
}
@Service
class CorrelationService {
private final RequestIdGenerator generator;
CorrelationService(RequestIdGenerator g) { this.generator = g; }
}
- A) Eine neue Prototype-Instanz bei jedem Methodenaufruf in CorrelationService
- B) Genau eine Prototype-Instanz, injiziert zum Zeitpunkt der CorrelationService-Erstellung
- C) Null; Prototype-Beans können nicht in Singletons injiziert werden
- D) Eine pro HTTP-Request automatisch ohne extra Konfiguration
Antwort & Erklärung
Richtige Antwort: B
Prototype in einen Singleton zu injizieren löst den Prototype einmal bei Singleton-Erstellung auf und verwendet dann dieselbe Referenz weiter. Der Singleton erhält nicht automatisch einen frischen Prototype pro Methodenaufruf oder Request. Für per-Request-Frische mit Singleton-Consumer: ObjectProvider, Scoped Proxy oder Lookup-Method-Injection.
Warum die anderen Optionen falsch sind:
- Prototype-Frische bei jedem Aufruf braucht ObjectProvider/getObject() oder Ähnliches, nicht plain Konstruktor-Injection.
- Injection ist erlaubt, fängt aber eine Instanz bei Singleton-Erstellung ein.
- Per-Request-Verhalten braucht Web-Scopes oder Scoped Proxies, nicht Default-Prototype-Injection allein.
Merksatz: „Prototype in Singleton = ein Prototype bei Singleton-Geburt eingefangen, kein laufendes Refresh."
Weiterlernen: Buchkapitel
Frage 15
Ein Entwickler fügt @Scope("request") zu einem Bean in einem Nicht-Web-Integrationstest hinzu, der nur @SpringBootTest mit NONE-Web-Environment nutzt. Was ist das wahrscheinliche Ergebnis?
- A) Spring fällt still auf Singleton-Scope zurück
- B) Der Bean wird einmal pro Testklasse erstellt
- C) Der Bean wird einmal pro JVM erstellt
- D) Context-Initialisierung schlägt fehl, weil Request-Scope einen Web-aware Context braucht
Antwort & Erklärung
Richtige Antwort: D
Request- und Session-Scopes hängen von Web-aware Lifecycle-Infrastruktur ab (RequestContextListener, DispatcherServlet usw.). In einem Nicht-Web-ApplicationContext schlägt die Registrierung eines Request-scoped Beans ohne Scoped Proxy oder Test-Web-Environment häufig beim Startup fehl. Spring downgradet Request-Scope nicht transparent zu Singleton.
Warum die anderen Optionen falsch sind:
- Spring remappt Request-Scope nicht automatisch zu Singleton in Nicht-Web-Contexts.
- Per-Testklasse-Verhalten ist nicht wie Request-Scope; es braucht einen aktiven Request.
- Request-Scope ist keine JVM-weite Singleton-Semantik.
Merksatz: „request/session-Scopes brauchen Web-aware Context oder Scoped-Proxy-Strategie."
Weiterlernen: Buchkapitel
Frage 16
Ein Bean implementiert sowohl @PostConstruct-Cleanup-Setup als auch InitializingBean.afterPropertiesSet(). In welcher Reihenfolge werden sie nach Property-Injection aufgerufen?
- A) @PostConstruct zuerst, dann afterPropertiesSet(), dann custom init-method falls deklariert
- B) afterPropertiesSet() zuerst, dann @PostConstruct
- C) Nur der Mechanismus, der früher in der Klassendatei steht, läuft
- D) Sie laufen parallel auf separaten Threads
Antwort & Erklärung
Richtige Antwort: A
Standard-Initialisierungsreihenfolge: Konstruktor, Dependency Injection, @PostConstruct, InitializingBean.afterPropertiesSet(), custom init-method, dann ist der Bean bereit. Diese Sequenz ist wichtig, wenn sowohl JSR-250 als auch Spring-Lifecycle-Interfaces vorhanden sind.
Warum die anderen Optionen falsch sind:
- InitializingBean läuft nach @PostConstruct, nicht davor.
- Beide Callbacks laufen, wenn beide vorhanden sind; Dateireihenfolge ist irrelevant.
- Initialisierung ist synchron auf dem erzeugenden Thread.
Merksatz: „Init-Reihenfolge: inject, dann @PostConstruct, dann InitializingBean, dann init-method."
Weiterlernen: Buchkapitel
Frage 17
Wann wird shutdown() auf dem ConnectionPool-Bean aufgerufen?
@Bean(destroyMethod = "shutdown")
public ConnectionPool connectionPool() {
return new ConnectionPool();
}
- A) Sofort nach Rückkehr der @Bean-Methode während Context-Refresh
- B) Nur wenn die JVM SIGTERM erhält, nie bei graceful Context-Close
- C) Während Container-Shutdown, wenn der Singleton zerstört wird
- D) Vor Dependency Injection in abhängige Beans
Antwort & Erklärung
Richtige Antwort: C
destroyMethod registriert einen custom Destroy-Callback, der ausgeführt wird, wenn der Application Context schließt und Singleton-Beans disposed werden. Es wird nicht direkt nach Factory-Method-Rückkehr aufgerufen. Spring inferiert auch Destroy-Methoden namens close oder shutdown standardmäßig, außer deaktiviert.
Warum die anderen Optionen falsch sind:
- Factory-Method-Rückkehr beginnt Bean-Leben; destroy läuft bei Context-Shutdown.
- Graceful Context-Close triggert Destroy-Callbacks, nicht nur OS-Signale.
- Destroy-Phase passiert, nachdem der Bean seinen Lifecycle erfüllt hat, nicht vor Injection.
Merksatz: „destroyMethod läuft bei Context-Close, nicht wenn die @Bean-Methode fertig ist."
Weiterlernen: Buchkapitel
Frage 18
Dieselbe Property ship.timeout ist in application.properties, einer OS-Umgebungsvariable SHIP_TIMEOUT und einem Command-Line-Argument --ship.timeout=90 definiert. Welcher Wert gewinnt mit default Spring Boot Precedence?
- A) application.properties, weil Dateien zuletzt laden
- B) Command-Line-Argumente überschreiben Umgebungsvariablen und Property-Dateien
- C) OS-Umgebungsvariablen schlagen Command-Line-Argumente in Boot 3 immer
- D) Der niedrigste numerische Wert unter den Quellen wird automatisch gewählt
Antwort & Erklärung
Richtige Antwort: B
Spring Boot Externalized Configuration folgt einer definierten Precedence-Kette: Command-Line-Argumente ranken über OS-Umgebungsvariablen, die über application.properties unter Defaults. Höhere Precedence-Quellen überschreiben niedrigere für dieselbe Property.
Warum die anderen Optionen falsch sind:
- Property-Dateien haben niedrigere Precedence als Environment und Command-Line in der Default-Kette.
- Umgebungsvariablen schlagen Dateien, aber nicht Command-Line-Argumente.
- Spring wählt Werte nicht per numerischem Vergleich über Quellen.
Merksatz: „Boot-Precedence-Highlight: Command Line schlägt Environment schlägt application.properties."
Weiterlernen: Buchkapitel
Frage 19
Warum könnte ein Team diese Auto-Configuration-Klassen in einem Batch-Worker ohne Datenbank ausschließen?
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class BatchWorkerApp { }
- A) Um Boot davon abzuhalten, DataSource- und JPA-Infrastruktur zu konfigurieren, wenn keine DB beabsichtigt ist
- B) Um Component Scanning nur für @Repository-Beans zu deaktivieren
- C) Um Actuator-Endpoints automatisch abzuschalten
- D) Weil @SpringBootApplication sonst @EnableAutoConfiguration nicht komponieren kann
Antwort & Erklärung
Richtige Antwort: A
Auto-Configuration backt ab, wenn Classpath-Conditions fehlschlagen, aber wenn JDBC/JPA-Libraries aus anderen Gründen vorhanden sind, kann Boot trotzdem eine DataSource konfigurieren. Explizites exclude verhindert ungewollte Infrastruktur und fehlgeschlagene DataSource-Erstellung ohne DB-URL. Es deaktiviert Scanning oder Actuator nicht von selbst.
Warum die anderen Optionen falsch sind:
- Auto-Config ausschließen deaktiviert nicht selektiv @Repository-Scanning.
- Actuator-Exposure wird über management-endpoints-Properties gesteuert, nicht diese Exclusions.
- @SpringBootApplication enthält bereits @EnableAutoConfiguration; exclude verfeinert es.
Merksatz: „exclude auf @SpringBootApplication nutzen, um spezifische Auto-Config-Klassen explizit zu vetoieren."
Weiterlernen: Buchkapitel
Frage 20
Ein custom MetricsRegistry-@Bean ist in User-Konfiguration deklariert. Eine Auto-Configuration-Klasse trägt @ConditionalOnMissingBean(MetricsRegistry.class). Was passiert?
- A) Beide Beans werden registriert und @Primary löst Mehrdeutigkeit
- B) Auto-Configuration gewinnt immer, weil sie zuerst lädt
- C) Der user-definierte MetricsRegistry verhindert die Registrierung des Auto-Config-Defaults
- D) Context schlägt mit doppelten Bean-Definitionen fehl
Antwort & Erklärung
Richtige Antwort: C
@ConditionalOnMissingBean ist eine Back-off-Regel: Wenn der Context bereits einen MetricsRegistry-Bean enthält (meist aus User-Config), wird der Auto-Config-Default übersprungen. Das ist das Extension-Point-Muster über Boot-Starter.
Warum die anderen Optionen falsch sind:
- Back-off vermeidet doppelte Beans; es erzeugt nicht zwei Defaults.
- User-Beans registrieren sich häufig in derselben Refresh-Phase; Missing-Bean-Condition evaluiert gegen existierende Definitionen.
- Duplicate-Failure würde ohne Condition auftreten; die Condition verhindert es.
Merksatz: „@ConditionalOnMissingBean = Auto-Config-Default überspringen, wenn User-Bean existiert."
Weiterlernen: Buchkapitel
Frage 21
Wo werden Auto-Configuration-Klassen in Spring Boot 3 primär für Discovery registriert?
- A) Nur in META-INF/spring.factories
- B) META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
- C) application.yml unter spring.auto-config.imports
- D) META-INF/beans.xml
Antwort & Erklärung
Richtige Antwort: B
Boot 3 verlagerte Auto-Configuration-Registrierung nach META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. spring.factories bleibt für einige Legacy-Extension-Hooks, aber Auto-Config-Listing migrierte. Diese Unterscheidung erscheint häufig in Prüfungen, die Boot 2 und 3 vergleichen.
Warum die anderen Optionen falsch sind:
- spring.factories war der Boot-2-Ort für EnableAutoConfiguration-Listing.
- Auto-Config-Klassenlisten werden nicht in application.yml deklariert.
- beans.xml ist Legacy-Spring-XML-Konfiguration, nicht Boot-Auto-Config-Discovery.
Merksatz: „Boot-3-Auto-Config-Imports-Datei liegt unter META-INF/spring/...AutoConfiguration.imports."
Weiterlernen: Buchkapitel
Frage 22
Im Vergleich zu @SpringBootApplication auf derselben Klasse — was fehlt in dieser Komposition?
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "com.acme.api")
public class ApiApplication { }
- A) Nichts; es ist in allen Boot-Versionen funktional identisch
- B) Nur @EnableAutoConfiguration fehlt
- C) Nur @ComponentScan fehlt
- D) Die Meta-Annotation wendet auch @EnableAutoConfigurationConfiguration-Alignment und Default-Scan-Verankerung an die deklarierende Klasse an, sofern nicht neu definiert
Antwort & Erklärung
Richtige Antwort: D
@SpringBootApplication kombiniert @SpringBootConfiguration, @EnableAutoConfiguration und @ComponentScan mit Default-Scan am Package der deklarierenden Klasse. Der gezeigte Code passt scan base an, lässt aber @SpringBootConfiguration-Semantik für die Configuration-Class-Rolle in Boot-Apps weg. Prüfungen testen die drei komponierten Concerns, auch wenn manuell nachgebaut.
Warum die anderen Optionen falsch sind:
- Manuelle Komposition kann in Defaults wie @SpringBootConfiguration und Scan-Verankerung abweichen.
- EnableAutoConfiguration ist im Snippet vorhanden.
- ComponentScan ist explizit mit custom Packages vorhanden.
Merksatz: „@SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan."
Weiterlernen: Buchkapitel
Frage 23
Mit spring-boot-starter-actuator auf dem Classpath und ohne custom Exposure-Einstellungen — welcher Endpoint ist in modernem Spring Boot standardmäßig über HTTP exposed?
- A) Nur /actuator/health (und /actuator/info in manchen Versionen mit Defaults)
- B) Alle Endpoints inklusive env, beans und shutdown
- C) Keine Actuator-Endpoints über HTTP, bis management.endpoints.web.exposure.include gesetzt ist
- D) Nur /actuator/prometheus
Antwort & Erklärung
Richtige Antwort: A
Standardmäßig exposed Boot eine minimale Web-Teilmenge aus Sicherheitsgründen. health ist der kanonische immer-exposed Endpoint; info kann je nach Version ebenfalls exposed sein. env, beans und shutdown brauchen explizite Exposure-Konfiguration.
Warum die anderen Optionen falsch sind:
- Alles standardmäßig zu exposen wäre ein Sicherheitsrisiko; Boot limitiert HTTP-Exposure.
- Einige Endpoints sind ohne custom include-Properties exposed.
- Prometheus-Export braucht Micrometer-Registry und explizite Exposure-Konfiguration.
Merksatz: „Default-HTTP-Actuator-Exposure ist minimal; health ist der zu merkende Endpoint."
Weiterlernen: Buchkapitel
Frage 24
Sowohl ApplicationRunner- als auch CommandLineRunner-Beans sind registriert. Wie ruft Spring sie relativ zueinander beim Startup auf?
- A) Nur CommandLineRunner läuft; ApplicationRunner ist deprecated
- B) Sie werden nie nach abgeschlossenem Context-Refresh aufgerufen
- C) Alle ApplicationRunner-Beans laufen vor CommandLineRunner-Beans; jede Gruppe sortiert per @Order oder Ordered
- D) Sie laufen interleaved alphabetisch nach Bean-Name
Antwort & Erklärung
Richtige Antwort: C
Nach Context-Refresh ruft Spring Boot ApplicationRunner-Callbacks auf, dann CommandLineRunner-Callbacks. Innerhalb jedes Typs steuert @Order/Ordered die Sequenz. Beide erhalten Kontrolle, nachdem der Context bereit ist, aber bevor die Anwendung als vollständig gestartet gilt.
Warum die anderen Optionen falsch sind:
- ApplicationRunner ist voll unterstützt und läuft in der ersten Runner-Phase.
- Beide Runner-Typen laufen nach Refresh; das ist ihr Zweck.
- Ordering ist per @Order innerhalb des Runner-Typs, nicht alphabetisch nach Bean-Namen.
Merksatz: „Startup-Runner: ApplicationRunner-Phase zuerst, dann CommandLineRunner."
Weiterlernen: Buchkapitel
Frage 25
Was ist die Hauptwirkung dieser Boot-Property in einer großen Web-Anwendung?
spring:
main:
lazy-initialization: true
- A) Beans werden nur bei erster Anforderung erstellt; Startup-Arbeit verzögert sich auf Kosten späterer Latenz beim ersten Zugriff
- B) Alle @Controller-Mappings sind deaktiviert, bis ein Warmup-Endpoint aufgerufen wird
- C) Auto-Configuration ist komplett deaktiviert
- D) Nur @Repository-Beans werden lazy; @Service-Beans bleiben eager
Antwort & Erklärung
Richtige Antwort: A
spring.main.lazy-initialization markiert Bean-Definitionen als lazy, sodass der Container sie bei erster Dependency Resolution oder explizitem getBean erstellt, nicht bei Refresh-Zeit. Das kann scheinbaren Startup beschleunigen, verschiebt aber Arbeit auf ersten Zugriff. Es gilt breit, nicht nur für bestimmte Stereotypes.
Warum die anderen Optionen falsch sind:
- Controller bleiben registriert; lazy init ändert Erstellungszeitpunkt, nicht Mapping-Registrierung selbst.
- Auto-Configuration läuft weiter; ihre Beans können lazy erstellt werden.
- Lazy Initialization ist eine globale Default-Verhaltensänderung, nicht stereotype-selektiv.
Merksatz: „lazy-initialization=true tauscht schnelleren Refresh gegen Verzögerung bei erster Bean-Erstellung."
Weiterlernen: Buchkapitel
Frage 26
Eine Auto-Configuration-Klasse trägt @ConditionalOnClass(name = "org.flywaydb.core.Flyway"). Die Flyway-Library fehlt auf dem Classpath. Was passiert?
- A) Auto-Configuration lädt trotzdem und schlägt zur Laufzeit bei erster Migration fehl
- B) Spring wirft ClassNotFoundException beim Application-Class-Loading der Auto-Config-Klasse
- C) Die Auto-Configuration-Klasse wird nicht angewendet, weil die Class-Condition false ist
- D) Spring lädt Flyway transitiv zur Laufzeit herunter
Antwort & Erklärung
Richtige Antwort: C
@ConditionalOnClass prüft Classpath-Präsenz mit String-Namen, um fehlende Typen nicht zu laden. Wenn Flyway fehlt, schlägt die Condition fehl und die Auto-Configuration backt ab, ohne Flyway-abhängige Beans zu laden. So bleiben optionale Integrationen sicher vom Classpath fern.
Warum die anderen Optionen falsch sind:
- Back-off verhindert Flyway-Beans, wenn die Library fehlt.
- String-basierte Klassennamen vermeiden hartes Laden fehlender Typen bei Condition-Evaluation.
- Spring löst fehlende Libraries nicht automatisch zur Laufzeit auf.
Merksatz: „@ConditionalOnClass backt gesamte Auto-Config ab, wenn die benannte Klasse fehlt."
Weiterlernen: Buchkapitel
Frage 27
Entwickler fügen spring-boot-devtools zu einem lokalen Profil hinzu und bemerken, dass die App bei Classpath-Klassenänderungen neu startet.
Welche Aussage über DevTools-Restart-Verhalten ist korrekt?
dependencies {
developmentOnly 'org.springframework.boot:spring-boot-devtools'
}
- A) DevTools lädt nur statische Resources neu; Java-Klassenänderungen brauchen immer vollen JVM-Exit
- B) DevTools nutzt zwei Classloader, sodass die meisten Classpath-Änderungen einen schnellen Application-Context-Restart in der Entwicklung triggern
- C) DevTools ist in Produktion standardmäßig aktiv, wenn die Dependency auf dem Runtime-Classpath liegt
- D) DevTools deaktiviert alle Auto-Configuration zum Beschleunigen von Restarts
Antwort & Erklärung
Richtige Antwort: B
Spring Boot DevTools teilt Base- und Restart-Classloader, sodass Code- und Resource-Änderungen einen schnellen Context-Restart statt kalten JVM-Boot triggern. Es ist für Entwicklung gedacht und sollte optional sein oder aus Produktions-Packaging ausgeschlossen werden. Es deaktiviert Auto-Configuration nicht.
Warum die anderen Optionen falsch sind:
- Java-Klassenänderungen sind genau das, wofür das Restart-Classloader-Modell schnell reagieren soll.
- DevTools sollte nicht in Produktion landen; developmentOnly oder optional scope nutzen.
- Auto-Configuration läuft nach DevTools-Restart weiter.
Merksatz: „DevTools = schneller Context-Restart via Dual-Classloader in der Entwicklung."
Weiterlernen: Buchkapitel
Frage 28
Welche HTTP-Pfade werden unter dem Default-Base-Path mit dieser Konfiguration verfügbar?
management:
endpoints:
web:
exposure:
include: health,metrics,beans
- A) Nur /health, /metrics und /beans am Server-Root
- B) /actuator/health, /actuator/metrics und /actuator/beans
- C) /management/health und verwandte Management-Pfade
- D) Alle Actuator-Endpoints unabhängig von der include-Liste
Antwort & Erklärung
Richtige Antwort: B
Web-Exposure-include whitelistet Actuator-Endpoints unter dem konfigurierbaren Base-Path, Default /actuator. Also health, metrics und beans unter /actuator/health, /actuator/metrics und /actuator/beans. Die include-Liste schränkt Endpoints ein; sie exposed nicht alles.
Warum die anderen Optionen falsch sind:
- Actuator-Endpoints hängen nicht standardmäßig am Server-Root.
- management ist nicht der Default-Base-Path-Segment.
- include ist eine Whitelist, kein implizites expose-all.
Merksatz: „Default-Actuator-Base-Path ist /actuator plus Endpoint-ID."
Weiterlernen: Buchkapitel
Frage 29
Ein Client sendet GET /api/v1/invoices/42 mit Accept: application/xml. Was ist das typische Ergebnis?
@RestController
@RequestMapping("/api/v1/invoices")
public class InvoiceController {
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public InvoiceDto get(@PathVariable Long id) { ... }
}
- A) 200-Antwort mit JSON-Body, weil produces den Handler auf JSON beschränkt
- B) 406 Not Acceptable, wenn kein Converter application/xml für diesen Handler befriedigen kann
- C) 200 mit XML, weil @RestController produces ignoriert
- D) 404 Not Found, weil Accept-Header nicht passt
Antwort & Erklärung
Richtige Antwort: B
produces schränkt Content-Types ein, die ein Handler erzeugen kann. Mit nur application/json und Accept: application/xml schlägt Content Negotiation fehl, einen kompatiblen Converter zu finden, und Spring MVC antwortet mit 406 Not Acceptable, außer es gibt breiteres produces oder einen zusätzlichen Converter.
Warum die anderen Optionen falsch sind:
- JSON wird zurückgegeben, wenn Negotiation JSON wählt; xml-Accept kollidiert mit json-only produces.
- @RestController respektiert produces auf Mapping-Methoden.
- Media-Type-Mismatch bei Negotiation ergibt 406, nicht 404.
Merksatz: „produces-Mismatch mit Accept führt zu 406, nicht zu stillem Format-Wechsel."
Weiterlernen: Buchkapitel
Frage 30
Im Spring-MVC-Request-Flow — was ist die primäre Verantwortung von DispatcherServlet?
- A) Front Controller, der Requests an Handler routet, Converter anwendet und Responses über die MVC-Infrastruktur rendert
- B) Compile-Time-Generierung von @RequestMapping-Annotationen
- C) Direkte JDBC-Ausführung für @Repository-Controller
- D) JPA-EntityManager-Lifecycle pro Request verwalten
Antwort & Erklärung
Richtige Antwort: A
DispatcherServlet ist der Front Controller, der HandlerMapping, HandlerAdapter, Argument Resolver, Message Converter und View Resolution koordiniert (für REST schreiben Message Converter Bodies). Er führt kein SQL aus und verwaltet JPA nicht direkt.
Warum die anderen Optionen falsch sind:
- Mapping-Annotationen sind Runtime-Metadaten, interpretiert von HandlerMapping-Beans.
- Datenzugriff gehört zu Repositories und Persistence-Layern, nicht DispatcherServlet.
- EntityManager-Lifecycle wird von JPA-Provider und Spring-Transaction-Infrastruktur gehandhabt.
Merksatz: „DispatcherServlet orchestriert MVC-Request-Handling End-to-End."
Weiterlernen: Buchkapitel
Frage 31
Ein Client ruft GET /products/search?category=books&page=2 auf. Welche Annotation bindet category und page in einer Controller-Methode?
- A) @PathVariable für beide Parameter
- B) @RequestHeader für beide Parameter
- C) Nur @ModelAttribute; Query-Strings können nicht an einfache Parameter binden
- D) @RequestParam für beide Parameter
Antwort & Erklärung
Richtige Antwort: D
Query-String-Key-Value-Paare binden mit @RequestParam (category, page) an Methodenparameter. @PathVariable bindet URI-Template-Segmente wie /products/{id}. @RequestHeader liest HTTP-Header.
Warum die anderen Optionen falsch sind:
- @PathVariable mappt URI-Template-Variablen, nicht Query-Parameter.
- Header sind nicht dort, wo category und page in dieser URL erscheinen.
- Einfache Query-Parameter binden direkt mit @RequestParam ohne Form-Objekt.
Merksatz: „Query-String-Parameter nutzen @RequestParam; URI-Segmente @PathVariable."
Weiterlernen: Buchkapitel
Frage 32
Der Client POSTet JSON mit quantity=0. Validierung ist mit spring-boot-starter-validation aktiviert. Was passiert vor Ausführung des Methodenbodys?
public record CreateOrderRequest(
@NotBlank String sku,
@Min(1) int quantity
) {}
@PostMapping("/orders")
public ResponseEntity<OrderId> create(@Valid @RequestBody CreateOrderRequest body) {
...
}
- A) Methode läuft; quantity 0 wird akzeptiert, weil Records Validierung überspringen
- B) 400 Bad Request via MethodArgumentNotValidException, gehandhabt von default MVC-Exception-Handling
- C) 500 Internal Server Error von Hibernate
- D) 201 Created mit korrigierter quantity, default 1
Antwort & Erklärung
Richtige Antwort: B
@Valid auf @RequestBody triggert Bean Validation auf Record-Feldern. @Min(1) schlägt für quantity=0 fehl und verursacht MethodArgumentNotValidException, typischerweise zu 400 übersetzt von Spring-MVC-Default-Exception-Handlern oder @ControllerAdvice.
Warum die anderen Optionen falsch sind:
- Records werden wie andere @RequestBody-Typen validiert, wenn @Valid vorhanden ist.
- Hibernate ist unrelated zu MVC-Request-Body-Validierungsfehlern.
- Spring korrigiert ungültige Eingaben nicht automatisch zu Success-Responses.
Merksatz: „@Valid @RequestBody-Fehler führen zu 400 MethodArgumentNotValidException."
Weiterlernen: Buchkapitel
Frage 33
Zwei @ControllerAdvice-Klassen definieren beide @ExceptionHandler für IllegalArgumentException. Eine ist mit @Order(Ordered.HIGHEST_PRECEDENCE) annotiert, die andere hat keine Order. Welcher Handler läuft zuerst?
- A) Der unordered Advice gewinnt immer
- B) Beide Handler laufen sequenziell für dieselbe Exception
- C) Die JVM wählt zufällig für loose coupling
- D) Der @Order(Ordered.HIGHEST_PRECEDENCE)-Advice wird früher in der Exception-Resolution konsultiert
Antwort & Erklärung
Richtige Antwort: D
@ControllerAdvice-Beans nehmen an geordneter Exception-Resolution teil. Niedrigere Order-Werte (höhere Precedence) werden zuerst betrachtet, wenn mehrere Handler anwendbar sein könnten. Nur ein Handler löst typischerweise eine gegebene Exception in einer Controller-Advice-Chain.
Warum die anderen Optionen falsch sind:
- Order priorisiert Advice explizit; unordered Defaults haben niedrigere Precedence als HIGHEST_PRECEDENCE.
- Eine einzelne Exception wird in normaler Resolution nicht wiederholt von mehreren @ExceptionHandler-Methoden desselben Typs behandelt.
- Resolution ist deterministisch basierend auf Order und Nähe-Regeln.
Merksatz: „Niedrigerer @Order-Wert auf @ControllerAdvice = höhere Precedence für Exception-Handling."
Weiterlernen: Buchkapitel
Frage 34
Bei erfolgreichem Löschen ohne Response-Body — welchen Status und Body erhält der Client?
@DeleteMapping("/accounts/{id}")
public ResponseEntity<Void> closeAccount(@PathVariable Long id) {
accountService.close(id);
return ResponseEntity.noContent().build();
}
- A) 204 No Content mit leerem Body
- B) 200 OK mit JSON {"status":"deleted"}
- C) 404 Not Found, außer ein Body wird geliefert
- D) 202 Accepted mit automatisch hinzugefügtem Location-Header
Antwort & Erklärung
Richtige Antwort: A
ResponseEntity.noContent() setzt HTTP 204 No Content — passend für erfolgreiches DELETE ohne Repräsentations-Body. Das ist idiomatisches REST für Delete-Erfolg ohne Payload.
Warum die anderen Optionen falsch sind:
- noContent().build() erzeugt keinen JSON-Body.
- Erfolgreiches Delete liefert hier 204, nicht 404.
- 202 Accepted ist für asynchrone Verarbeitungsannahme, nicht sofortiges erfolgreiches Delete.
Merksatz: „Erfolgreiches DELETE ohne Payload: ResponseEntity.noContent() gibt 204."
Weiterlernen: Buchkapitel
Frage 35
Ein REST-Client sendet Accept: application/json, application/xml;q=0.9. Der Controller-Handler kann sowohl JSON als auch XML produzieren. Was bestimmt das Response-Format?
- A) Immer JSON, weil @RestController nur JSON impliziert
- B) Die erste deklarierte @GetMapping-Methode in der Klasse
- C) Content Negotiation mit Accept-Header-q-Werten und verfügbaren HttpMessageConverter-Typen
- D) Ausschließlich der Content-Type-Request-Header
Antwort & Erklärung
Richtige Antwort: C
Spring-MVC-Content-Negotiation wählt einen Output-Media-Type, kompatibel mit Accept-Präferenzen und unterstützt von registrierten Converters (Jackson für JSON, JAXB/Jackson XML für XML). q-Werte drücken Client-Präferenz aus. Content-Type beschreibt primär den Request-Body, nicht Response-Format-Auswahl.
Warum die anderen Optionen falsch sind:
- @RestController nutzt Message Converter, kann aber mehrere Media Types produzieren, wenn konfiguriert.
- Methoden-Deklarationsreihenfolge treibt Negotiation nicht.
- Response-Format-Auswahl nutzt Accept und produces-Fähigkeiten, nicht inbound Content-Type allein.
Merksatz: „Response-Format kommt von Accept-Negotiation plus Converter-Support."
Weiterlernen: Buchkapitel
Frage 36
Ein Formular postet application/x-www-form-urlencoded-Felder an eine @Controller-Methode. Welche Annotation bindet Felder in einen Command-Object-Parameter?
- A) @RequestBody
- B) @RequestPart
- C) @ResponseBody
- D) @ModelAttribute
Antwort & Erklärung
Richtige Antwort: D
@ModelAttribute bindet Formularfelder und Query-Parameter an Objekt-Properties für Nicht-JSON-Requests. @RequestBody ist für Message-Converter-Bodies wie JSON/XML. @RequestPart ist für Multipart-Parts.
Warum die anderen Optionen falsch sind:
- @RequestBody erwartet konvertierten Message-Body (JSON/XML), nicht standard Form-Encoding by default.
- @RequestPart zielt auf Multipart-Sections, nicht einfache Form-Posts.
- @ResponseBody serialisiert Rückgabewerte; es bindet keine eingehenden Formulardaten.
Merksatz: „HTML-Formular- und Query-Binding an Objekte nutzt @ModelAttribute."
Weiterlernen: Buchkapitel
Frage 37
Warum eine read-only Reporting-Methode mit @Transactional(readOnly = true) markieren?
@Service
public class ReportService {
@Transactional(readOnly = true)
public List<Summary> summarize() {
return repo.findAll().stream().map(mapper::toSummary).toList();
}
}
- A) Es ist erforderlich, sonst werfen Spring-Data-Repositories IllegalStateException
- B) Es signalisiert Transaction Manager und JPA-Provider, unnötige Dirty Checks und Flush zu vermeiden — Optimierung für Read-Pfade
- C) Es fügt automatisch DB-Row-Level-Shared-Locks für jedes Select hinzu
- D) Es routet Queries ohne extra Konfiguration zu einer beschreibbaren Replica-DataSource
Antwort & Erklärung
Richtige Antwort: B
readOnly=true ist ein Optimierungshinweis: Hibernate kann Dirty Checking und Flush überspringen, manche Treiber optimieren read-only Transactions. Es routet nicht von selbst zu Replicas oder fügt Locks hinzu. Writes in readOnly-Transaction können je nach Provider fehlschlagen oder inkonsistent sein.
Warum die anderen Optionen falsch sind:
- Repositories brauchen readOnly nicht universell für Queries.
- readOnly erzwingt keine Shared Locks auf allen Selects by default.
- Read-Replica-Routing braucht explizite Routing-DataSource-Konfiguration.
Merksatz: „readOnly=true optimiert Read-Transactions; es ist kein magisches Replica-Routing."
Weiterlernen: Buchkapitel
Frage 38
Innerhalb einer einzelnen @Transactional-Methode wird repository save() aufgerufen, dann läuft eine Query vor Methodenende. Wann werden INSERT-Statements typischerweise zur DB geflusht?
- A) Vor der Query, wenn der Persistence Provider den Persistence-Context-State mit der DB synchronisieren muss, um Query-Visibility-Semantik zu erfüllen
- B) Nie bis die JVM beendet wird
- C) Nur wenn @Modifying auf der Query vorhanden ist
- D) Sofort bei jedem save()-Aufruf immer, unabhängig von Transaction-Grenzen
Antwort & Erklärung
Richtige Antwort: A
JPA kann vor Queries auto-flushen, damit In-Memory-Änderungen für Query-Ausführung im selben Persistence Context sichtbar sind. Flush-Timing hängt von Flush Mode und Provider ab; es wird nicht bis JVM-Exit aufgeschoben. save() bedeutet nicht immer sofortiges SQL ohne Flush.
Warum die anderen Optionen falsch sind:
- Persistence-Context-Änderungen werden während Transaction-Arbeit geflusht, nicht bei JVM-Shutdown.
- @Modifying betrifft Update/Delete-Queries, nicht grundlegendes Flush-before-Select-Verhalten.
- Flush kann Writes batchen; Auto-Flush vor Queries ist häufig, aber nicht identisch mit per-save sofortigem Commit.
Merksatz: „JPA kann pending Änderungen vor Queries in derselben Transaction auto-flushen."
Weiterlernen: Buchkapitel
Frage 39
Ein Spring-Data-JPA-Repository deklariert @Modifying @Query("delete from Inventory i where i.expired = true"). Was ist für korrekte Ausführung erforderlich?
- A) Nur @Cacheable auf dem Repository-Interface
- B) Eine umgebende @Transactional (oder transaktionale Service-Methode), damit das Delete in einer Transaction läuft und clearAutomatically-Semantik wie konfiguriert gilt
- C) @Async auf der Query-Methode
- D) Manueller EntityManager only; @Query delete wird nicht unterstützt
Antwort & Erklärung
Richtige Antwort: B
@Modifying-Queries ändern DB-State und müssen innerhalb einer Transaction laufen. Spring-Data-Dokumentation verlangt @Transactional auf der modifying method oder dem aufrufenden Service. clearAutomatically/Flushing-Verhalten hängt auch vom transaktionalen EntityManager-State ab.
Warum die anderen Optionen falsch sind:
- @Cacheable ist unrelated zur Ausführung von Bulk-DML-Queries.
- @Async ersetzt nicht transaktionale Anforderungen für modifying queries.
- Spring Data unterstützt @Modifying @Query delete vollständig.
Merksatz: „@Modifying-Queries brauchen einen aktiven Transaction-Context."
Weiterlernen: Buchkapitel
Frage 40
Der Service läuft in einer einzelnen read-only Transaction und sieht 51 SQL-Statements für Orders plus Items. Was ist der beste Fix?
@Entity
public class Order {
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
private List<LineItem> items;
}
// Service lädt 50 Orders, greift dann auf order.getItems() für jedes zu
- A) Alle Entities global auf FetchType.EAGER ändern
- B) @Transactional(propagation = REQUIRES_NEW) auf den Accessor hinzufügen
- C) Fetch Join oder @EntityGraph in der Query, die Orders lädt
- D) JPA nur durch JDBC ersetzen
Antwort & Erklärung
Richtige Antwort: C
Das ist das klassische N+1-Select-Problem: eine Query für Orders plus eine pro Order für lazy items. Fetch Join oder @EntityGraph lädt Assoziationen in der initialen Query innerhalb der Transaction. Globales EAGER verursacht andere Performance-Probleme. REQUIRES_NEW batcht Assoziationen nicht.
Warum die anderen Optionen falsch sind:
- Globales EAGER over-fetcht oft und schadet Performance anderswo.
- REQUIRES_NEW ändert Transaction-Grenzen, nicht Assoziations-Lade-Strategie.
- JPA ist in Ordnung, wenn Fetching getunt ist; JDBC ist nicht die erforderliche Prüfungsantwort.
Merksatz: „N+1-Fix in JPA: Fetch Join oder @EntityGraph in der initialen Query."
Weiterlernen: Buchkapitel
Frage 41
Welche abgeleitete Query-Methodensignatur matcht korrekt Entities, bei denen lastName dem Parameter entspricht (Groß-/Kleinschreibung ignorierend)?
- A) findByLastNameCaseInsensitive(String lastName)
- B) findByLastNameIgnoreCase(String lastName)
- C) findByLastNameLikeIgnoreCase(String lastName)
- D) findLastNameIgnoreCase(String lastName)
Antwort & Erklärung
Richtige Antwort: B
Spring-Data-JPA-abgeleitete Query-Keywords enthalten IgnoreCase für case-insensitive Equality auf String-Properties. Korrekte Reihenfolge: findBy + Property + IgnoreCase. Like impliziert Pattern Matching, nicht einfache Equality.
Warum die anderen Optionen falsch sind:
- CaseInsensitive ist nicht das unterstützte Keyword; IgnoreCase ist es.
- LikeIgnoreCase zielt auf Pattern-Predicates, nicht plain equals ignoring case.
- findLastNameIgnoreCase lässt das erforderliche By-Separator nach find weg.
Merksatz: „IgnoreCase ist das Spring-Data-Keyword für case-insensitive Property-Matching."
Weiterlernen: Buchkapitel
Frage 42
publish() wird von einem Controller aufgerufen. Warum könnte postEntry() ohne Transaction-Grenze laufen?
@Service
public class LedgerService {
@Transactional
private void postEntry() { ledgerRepo.save(entry); }
public void publish() { postEntry(); }
}
- A) @Transactional auf privaten Methoden wird von Spring-AOP-Proxy-basiertem Transaction Management ignoriert
- B) Private Methoden sind immer REQUIRES_NEW
- C) Controller suspendieren automatisch Transactions
- D) ledgerRepo.save startet immer seine eigene required Transaction, sodass @Transactional unnötig ist
Antwort & Erklärung
Richtige Antwort: A
Spring wendet @Transactional via Proxies an, die public Methoden auf proxied Beans abfangen. Self-Invocation privater @Transactional-Methoden umgeht den Proxy, sodass kein Transaction Advice läuft. Fix: Methode public machen, Transaction-Grenze in anderen Bean verschieben oder AspectJ Weaving nutzen.
Warum die anderen Optionen falsch sind:
- Private Methoden werden nicht automatisch REQUIRES_NEW.
- Controller suspendieren Service-Layer-Transaction-Demarcation nicht von selbst.
- Repository save nimmt an einer Transaction teil, nur wenn eine existiert oder mit Propagation konfiguriert; das private-Method-Problem bleibt.
Merksatz: „@Transactional auf privaten Methoden wird über Standard-Spring-Proxies nicht angewendet."
Weiterlernen: Buchkapitel
Frage 43
Ein managed Shipment mit zwei Parcel-Children wird via repository.save(shipment) gespeichert. Später wird ein Parcel aus der Liste entfernt und erneut save aufgerufen. Was passiert mit dem entfernten Parcel?
@Entity
public class Shipment {
@OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true)
private List<Parcel> parcels = new ArrayList<>();
}
- A) Es bleibt in der DB, weil cascade PERSIST Deletes nicht handhabt
- B) Nur die Shipment-Zeile wird aktualisiert; Parcel-Zeilen sind immutable
- C) orphanRemoval löscht die detached Parcel-Zeile, wenn die Assoziation geleert wird und Änderungen flushen
- D) JPA wirft UnsupportedOperationException für orphanRemoval mit Listen
Antwort & Erklärung
Richtige Antwort: C
orphanRemoval=true löscht Child-Entities, die aus der Collection entfernt werden, wenn der Parent managed ist und Änderungen synchronisieren. CascadeType.PERSIST propagiert persist zu neuen Children, orphanRemoval deckt Entfernung aus der Assoziation ab. save triggert Flush innerhalb der Transaction.
Warum die anderen Optionen falsch sind:
- orphanRemoval adressiert speziell Child-Entfernung aus der Collection.
- Parcel-Zeilen können durch orphanRemoval-Semantik gelöscht werden.
- orphanRemoval mit @OneToMany-Listen wird unterstützt, wenn properly managed.
Merksatz: „orphanRemoval löscht Children, die aus der Parent-Collection entfernt werden, beim Flush."
Weiterlernen: Buchkapitel
Frage 44
Wann solltest du saveAndFlush(entity) save(entity) vorziehen in Spring Data JPA?
- A) Für jede read-only Query zur Cache-Verbesserung
- B) Nie; sie sind in allen Providern identisch
- C) Wenn nachfolgende Logik in derselben Transaction SQL sofort triggern muss, damit Constraints oder Queries persistierten State sehen
- D) Nur bei MongoDB-Repositories
Antwort & Erklärung
Richtige Antwort: C
save kann SQL bis Flush-Zeit aufschieben. saveAndFlush erzwingt sofortige Synchronisation mit der DB innerhalb der aktuellen Transaction — nützlich vor abhängigen Queries oder Constraint-Checks, die Rows jetzt brauchen.
Warum die anderen Optionen falsch sind:
- Read-only Queries brauchen kein save oder flush.
- save kann SQL verzögern; Verhalten unterscheidet sich beim Flush-Timing.
- saveAndFlush ist JPA-Repository-Concern, nicht MongoDB.
Merksatz: „saveAndFlush erzwingt SQL jetzt; save kann bis Flush warten."
Weiterlernen: Buchkapitel
Frage 45
Was erzwingt diese SecurityFilterChain-Konfiguration für GET /api/orders?
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
}
- A) Authentifizierung ist erforderlich; unauthentifizierte Requests werden gemäß Entry-Point-Regeln abgelehnt
- B) Alle Requests inklusive /api/orders sind anonym, weil CSRF deaktiviert ist
- C) Nur HTTPS wird erzwungen; Authentifizierung ist optional
- D) GET-Requests umgehen Security-Filter komplett
Antwort & Erklärung
Richtige Antwort: A
anyRequest().authenticated() verlangt einen authentifizierten Principal für /api/orders. permitAll gilt nur für gematchte Pfade wie /actuator/health. CSRF deaktivieren deaktiviert Authentifizierung nicht. HTTP-Method-spezifischer Bypass ist nicht konfiguriert.
Warum die anderen Optionen falsch sind:
- CSRF disable betrifft Cross-Site-Request-Forgery-Schutz, nicht Authentifizierungsanforderungen.
- HTTPS-Erzwingung würde requiresChannel oder externe Konfiguration nutzen, hier nicht gezeigt.
- Security-Filter laufen weiter; GET ist nicht global permitted.
Merksatz: „permitAll-Matcher sind Ausnahmen; anyRequest().authenticated() sichert den Rest."
Weiterlernen: Buchkapitel
Frage 46
Passwörter müssen mit adaptivem Hashing und automatischer Salt-Behandlung gespeichert werden. Welcher Encoder ist die Spring-Security-Default-Empfehlung?
- A) NoOpPasswordEncoder für Klartext in allen Environments
- B) MD5PasswordEncoder für Geschwindigkeit
- C) BCryptPasswordEncoder
- D) Base64-Encoding ohne Hashing
Antwort & Erklärung
Richtige Antwort: C
BCryptPasswordEncoder bietet adaptives One-Way-Hashing mit Salt gegen Rainbow-Table-Angriffe. NoOp und MD5 sind unsicher oder deprecated. Base64 ist Encoding, keine sichere Passwort-Speicherung.
Warum die anderen Optionen falsch sind:
- NoOpPasswordEncoder ist nur für Legacy-Tests, nie Produktions-Default.
- MD5 wird für Passwort-Speicherung nicht empfohlen.
- Base64 ist reversibles Encoding, kein Passwort-Hashing.
Merksatz: „Passwörter mit BCryptPasswordEncoder speichern, nicht Encoding oder schnelle Hashes."
Weiterlernen: Buchkapitel
Frage 47
Method Security nutzt @PreAuthorize("hasRole('ADMIN')"). Wie sollten Rollen in UserDetails-Authorities gespeichert sein, damit dieser Check besteht?
- A) Exakt „ADMIN" ohne Prefix
- B) Als „ROLE_ADMIN", weil hasRole das ROLE_-Prefix beim Vergleich hinzufügt
- C) Als „role.admin" lowercase dotted form
- D) Authorities werden ignoriert; nur der Username zählt
Antwort & Erklärung
Richtige Antwort: B
hasRole("ADMIN") expandiert zu ROLE_ADMIN-Authority-Vergleich. GrantedAuthority-Werte sollten ROLE_ADMIN enthalten (oft via roles mit Default-Prefix). hasAuthority("ADMIN") würde literal ADMIN ohne ROLE_ matchen.
Warum die anderen Optionen falsch sind:
- hasRole erwartet intern ROLE_-prefixed Authorities.
- Dotted lowercase ist nicht die Default-Spring-Security-Rollen-Konvention.
- Authorities treiben Autorisierungsentscheidungen.
Merksatz: „hasRole("ADMIN") prüft auf Authority ROLE_ADMIN."
Weiterlernen: Buchkapitel
Frage 48
Diese Konfiguration zielt auf eine stateless JWT-API. Warum ist CSRF hier deaktiviert?
http
.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
- A) CSRF-Schutz ist irrelevant für sessionlose APIs mit Token-Authentifizierung ohne Browser-Cookie-Session-Semantik
- B) CSRF muss immer deaktiviert sein, sonst startet Spring Security nicht
- C) JWT enthält automatisch CSRF-Tokens in jedem Header
- D) CSRF gilt nur für POST und DELETE, nie GET
Antwort & Erklärung
Richtige Antwort: A
CSRF schützt Cookie-basierte Session-Apps vor Cross-Site-Requests. Stateless Token-APIs ohne Browser-verwaltete Session-Cookies deaktivieren CSRF häufig, weil Angreifer custom Authorization-Header nicht leicht erzwingen können. Das ist nicht universal für alle Apps.
Warum die anderen Optionen falsch sind:
- Spring Security startet mit aktiviertem CSRF; disable ist eine bewusste API-Wahl.
- JWT ersetzt CSRF-Schutz für Cookie-Sessions nicht automatisch.
- CSRF kann state-changing Requests in Browser-Apps breit betreffen; Disable-Rationale hier ist Statelessness.
Merksatz: „Stateless Token-APIs deaktivieren CSRF oft; Cookie-Sessions sollten CSRF aktiviert lassen."
Weiterlernen: Buchkapitel
Frage 49
Bei Form-Login — welche Komponente lädt User-Credentials, Rollen und Account-Flags für Authentifizierung?
- A) UserDetailsService
- B) Nur PasswordEncoder
- C) HandlerMapping
- D) DispatcherServlet
Antwort & Erklärung
Richtige Antwort: A
UserDetailsService lädt UserDetails per Username für Authentication Managers zur Passwort- und Account-State-Validierung. PasswordEncoder verifiziert Passwort-Hashes, lädt aber keine User. MVC-Servlet-Komponenten sind unrelated.
Warum die anderen Optionen falsch sind:
- PasswordEncoder hasht und matched Passwörter; er fetcht keine User.
- HandlerMapping routet Web-Requests.
- DispatcherServlet ist MVC Front Controller, nicht Security User Loading.
Merksatz: „UserDetailsService lädt User; PasswordEncoder verifiziert Passwörter."
Weiterlernen: Buchkapitel
Frage 50
Welche Annotation aktiviert JSR-250-Style @RolesAllowed auf der Service-Layer mit Spring Security Method Security?
- A) Nur @EnableWebSecurity
- B) @Secured auf Methoden ohne Enable-Annotation
- C) @EnableMethodSecurity (oder legacy @EnableGlobalMethodSecurity) mit securedEnabled/jsr250Enabled nach Bedarf
- D) @Transactional
Antwort & Erklärung
Richtige Antwort: C
@EnableMethodSecurity aktiviert Method-Level-Security inklusive @Secured, @PreAuthorize und JSR-250-Annotationen, wenn jsr250Enabled konfiguriert ist. @EnableWebSecurity allein konfiguriert HTTP-Security-Filter, nicht Method-Interception.
Warum die anderen Optionen falsch sind:
- @EnableWebSecurity konfiguriert die Filter Chain, nicht Method-Annotationen allein.
- @Secured braucht aktivierte Method Security zur Durchsetzung durch Spring.
- @Transactional verwaltet Transactions, nicht Autorisierungs-Annotationen.
Merksatz: „Method Security braucht @EnableMethodSecurity plus das gewählte Annotation-Modell."
Weiterlernen: Buchkapitel
Frage 51
Welche Beans sind im Test-ApplicationContext vorhanden?
@WebMvcTest(InvoiceController.class)
class InvoiceControllerTest {
@Autowired MockMvc mockMvc;
@MockBean InvoiceService invoiceService;
}
- A) Die volle Anwendung inklusive JPA-Repositories und DataSource-Auto-Config
- B) Nur Web-Layer-MVC-Infrastruktur, Jackson und InvoiceController mit InvoiceService durch Mock ersetzt
- C) Kein Spring-Context; nur pure Unit-Tests ohne MVC
- D) Nur @Repository-Beans für Slice-Isolation
Antwort & Erklärung
Richtige Antwort: B
@WebMvcTest lädt einen schmalen MVC-Slice: Controller, MVC-Config, Jackson, Exception Handler usw., aber nicht den vollen Data Layer. @MockBean ersetzt fehlende Collaborators wie InvoiceService. Das hält Controller-Tests schnell und fokussiert.
Warum die anderen Optionen falsch sind:
- Voller @SpringBootTest-Context enthält Data Layer; @WebMvcTest schließt ihn aus.
- MockMvc und @Autowired beweisen einen Spring-Test-Context.
- @DataJpaTest ist der Repository-Slice, nicht @WebMvcTest.
Merksatz: „@WebMvcTest = MVC-Stack plus Controller unter Test; Collaborators mit @MockBean gemockt."
Weiterlernen: Buchkapitel
Frage 52
Ein @MockBean ersetzt einen existierenden MyService-Bean in @SpringBootTest. Was macht Spring?
- A) Erzeugt einen zweiten MyService; Injection schlägt wegen Mehrdeutigkeit fehl
- B) Ignoriert @MockBean, außer @InjectMocks ist auch vorhanden
- C) Läuft den Test ohne Spring-Context
- D) Entfernt oder überschreibt die originale Bean-Definition, sodass Dependents den Mockito-Mock erhalten
Antwort & Erklärung
Richtige Antwort: D
@MockBean registriert einen Mockito-Mock im Test-Context und ersetzt jeden Bean desselben Typs oder erzeugt einen, wenn fehlend. Abhängige Beans erhalten dann den Mock bei Injection. Es integriert Mockito mit Spring-Test-Contexts.
Warum die anderen Optionen falsch sind:
- Replacement vermeidet doppelte Mehrdeutigkeit für den targeted Bean.
- @MockBean funktioniert ohne @InjectMocks; letzteres ist für plain Mockito-Tests.
- @MockBean braucht einen Spring-Test-Context zur Mock-Bean-Registrierung.
Merksatz: „@MockBean legt einen Mockito-Mock in den Spring-Test-ApplicationContext."
Weiterlernen: Buchkapitel
Frage 53
Was gilt standardmäßig über @DataJpaTest?
- A) Es konfiguriert In-Memory-DB, JPA-Test-Slice und rollt Transactions nach jeder Testmethode zurück, außer @Commit wird genutzt
- B) Es startet den gesamten Servlet-Container und alle Controller
- C) Es nutzt nie @Transactional
- D) Es verlangt Docker Testcontainers für jeden Run
Antwort & Erklärung
Richtige Antwort: A
@DataJpaTest auto-konfiguriert JPA, embedded DB wenn verfügbar und @Transactional Test-Rollback by default für Isolation. Es ist kein voller Web- oder Integration-Test-Slice und mandate Testcontainers nicht.
Warum die anderen Optionen falsch sind:
- Servlet-Container und Controller gehören zu @SpringBootTest oder @WebMvcTest-Slices.
- Tests sind standardmäßig @Transactional für Rollback.
- Testcontainers sind optional für echte DB-Integration, keine Default-Anforderung.
Merksatz: „@DataJpaTest = JPA-Slice, embedded DB, transaktionaler Rollback pro Test."
Weiterlernen: Buchkapitel
Frage 54
Was konfiguriert RANDOM_PORT für diesen Integrationstest?
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiIT {
@Autowired TestRestTemplate rest;
}
- A) Kein Webserver; TestRestTemplate ist nicht nutzbar
- B) Nur fester Port 8080
- C) Embedded Webserver startet auf zufälligem freien Port; TestRestTemplate kann echte HTTP-Endpoints aufrufen
- D) Mockt DispatcherServlet ohne Sockets zu öffnen
Antwort & Erklärung
Richtige Antwort: C
RANDOM_PORT startet den embedded Servlet-Container auf ephemeral Port und ermöglicht volle HTTP-Integrationstests mit TestRestTemplate oder WebTestClient. DEFINED_PORT nutzt server.port; NONE überspringt Web-Environment.
Warum die anderen Optionen falsch sind:
- RANDOM_PORT startet definitiv einen Webserver.
- Port ist zufällig, nicht hard-coded 8080.
- Echte Sockets werden für HTTP-Integrationstests genutzt.
Merksatz: „WebEnvironment.RANDOM_PORT bootet embedded Server auf ephemeral Port."
Weiterlernen: Buchkapitel
Frage 55
Du brauchst extra Test-only-Beans ohne Produktions-@Configuration zu verschmutzen. Welcher Ansatz ist idiomatisch?
- A) @Import auf der Main-@SpringBootApplication-Klasse in src/main/java
- B) Statische @TestConfiguration-Inner-Class oder separate Test-Konfiguration, vom Test importiert
- C) Produktions-Beans mit Reflection in @BeforeEach modifizieren
- D) Spring-Test-Context deaktivieren und nur @ExtendWith(MockitoExtension.class) für Integrationstests
Antwort & Erklärung
Richtige Antwort: B
@TestConfiguration wird nur verarbeitet, wenn explizit importiert oder in Tests entdeckt — Test-Doubles bleiben aus Main-Konfiguration. Es kann @Bean-Methoden für Mocks, Stubs oder Fakes in Integrationstests definieren.
Warum die anderen Optionen falsch sind:
- Produktions-Main-Konfiguration sollte keine Test-only-Beans importieren.
- Reflection-Hacks sind brüchig und nicht idiomatisches Spring-Testing.
- Integrationstests brauchen Spring-Context; MockitoExtension allein ist für Unit-Tests.
Merksatz: „Test-only-Beans gehören in @TestConfiguration, vom Test importiert."
Weiterlernen: Buchkapitel
Frage 56
Ein Entwickler nutzt @InjectMocks in einem plain JUnit-5-Test ohne Spring. Welche Aussage ist korrekt?
- A) @InjectMocks erzeugt und injiziert Mocks in die Klasse unter Test in puren Mockito-Tests ohne Spring-Start
- B) @InjectMocks funktioniert nur innerhalb @SpringBootTest
- C) @InjectMocks ersetzt @MockBean im Spring-Test-Context automatisch
- D) @InjectMocks lädt application.yml Property-Bindings
Antwort & Erklärung
Richtige Antwort: A
@InjectMocks ist eine Mockito-Annotation, die das Test-Subject konstruiert und @Mock/@Spy-Collaborators ohne Spring injiziert. @MockBean ist das Spring-TestContext-Integrations-Pendant, das Beans im Context registriert.
Warum die anderen Optionen falsch sind:
- @InjectMocks wird häufig ohne Spring in Unit-Tests genutzt.
- @MockBean ist separat; @InjectMocks registriert keine Spring-Beans.
- Property-Binding ist unrelated zu Mockito-Injection.
Merksatz: „@InjectMocks ist Mockito-only; @MockBean ist Spring-Test-Context-Integration."
Weiterlernen: Buchkapitel
Frage 57
Ein anderer Bean ruft transferService.transfer() auf. Warum läuft internal() ohne Transaction-Grenze?
@Service
public class TransferService {
public void transfer() { internal(); }
@Transactional
public void internal() { /* JDBC work */ }
}
- A) Self-Invocation umgeht den Proxy, sodass @Transactional auf internal() nicht angewendet wird, wenn transfer() es direkt innerhalb derselben Klasse aufruft
- B) @Transactional gilt nur für @Repository-Klassen
- C) internal() läuft trotzdem in einer Transaction, weil transfer() durch den Proxy aufgerufen wurde
- D) Spring merged benachbarte Methoden immer in eine Transaction-Grenze unabhängig von Sichtbarkeit
Antwort & Erklärung
Richtige Antwort: A
Der externe Aufruf tritt transfer() durch den Proxy ein, aber transfer() ruft dann internal() direkt auf this auf. Dieser innere Aufruf geht nicht durch den Proxy, sodass das @Transactional-Advice auf internal() nie läuft. Transactionale Methode in anderen Bean verschieben, self injizieren oder AspectJ Weaving nutzen.
Warum die anderen Optionen falsch sind:
- @Transactional gilt für jede Spring-verwaltete Bean-Methode, nicht nur Repositories.
- Der Proxy wrappt nur die von außen aufgerufene Methode (transfer()); er berät internal() bei Same-Class-Call nicht retroaktiv.
- Sichtbarkeit oder Adjazenz verursacht kein automatisches Transactional-Merging bei Self-Calls.
Merksatz: „Self-Invocation überspringt Spring-AOP-Proxies — @Transactional und andere Aspects brechen."
Weiterlernen: Buchkapitel
Frage 58
Eine Methode ist mit @Async auf einem Bean in einer Boot-App mit @EnableAsync annotiert. Welcher Executor läuft sie standardmäßig, wenn keiner customisiert ist?
- A) Immer ForkJoinPool.commonPool()
- B) Ein neuer Thread pro Aufruf ohne Pool
- C) SimpleAsyncTaskExecutor oder TaskExecutor-Bean je nach Konfiguration; Boot bietet Async-Support, custom Executor braucht TaskExecutor-Bean-Definition
- D) Der HTTP-Request-Thread läuft synchron weiter, außer @Transactional ist vorhanden
Antwort & Erklärung
Richtige Antwort: C
@EnableAsync aktiviert Proxy-basierte Async-Ausführung. Ohne custom Executor nutzt Spring einen Default-SimpleAsyncTaskExecutor (neuer Thread pro Task im klassischen Setup), außer ein TaskExecutor-Bean ist definiert. Boot läuft @Async nicht still auf dem aufrufenden HTTP-Thread.
Warum die anderen Optionen falsch sind:
- Default ist nicht für alle @Async-Setups garantiert commonPool.
- SimpleAsyncTaskExecutor-Verhalten ist executor-basiert, nicht strikt One-Off-Threads in allen Versionen, aber trotzdem keine synchrone HTTP-Thread-Fortsetzung.
- @Transactional steuert nicht @Async-Dispatch-Semantik.
Merksatz: „@Async braucht @EnableAsync; Async mit TaskExecutor-Bean customisieren."
Weiterlernen: Buchkapitel
Frage 59
ApplicationEventPublisher.publishEvent(new OrderPlacedEvent(orderId)) wird von einem Service aufgerufen. Was sind die Default-Listener-Invocation-Semantiken in Spring, außer @Async ist auf dem Listener angewendet?
- A) Listener laufen sofort auf Background-Thread
- B) Das Event wird in der DB persistiert, bevor Listener laufen
- C) Listener führen synchron im Publishing-Thread aus, nachdem die Publisher-Methode publishEvent erreicht
- D) Events werden verworfen, außer @EventListener ist auf einem @Controller
Antwort & Erklärung
Richtige Antwort: C
Default Spring Application Events sind synchron: Listener laufen im Caller-Thread, außer der Listener ist @Async mit aktiviertem Async. Events sind standardmäßig in-memory, nicht auto-persistiert, und @EventListener funktioniert auf jedem Bean.
Warum die anderen Optionen falsch sind:
- Background-Invocation braucht @Async oder anwendungsspezifische Async-Konfiguration.
- Event-Publikation impliziert keine automatische DB-Persistenz.
- @EventListener wird auf jedem managed Bean unterstützt, nicht nur Controllern.
Merksatz: „Spring Events sind standardmäßig synchron im Publishing-Thread."
Weiterlernen: Buchkapitel
Frage 60
Ein Team exportiert Application-Metrics zu Prometheus und überwacht JVM-Memory via Micrometer in Boot. Welcher Integrationspunkt ist am relevantesten?
- A) Nur custom JSP-Tags
- B) Nur Logback-XML-Appender ohne Actuator
- C) @Metric auf jeder Controller-Methode manuell deklarieren
- D) Actuator-Metrics-Endpoint und Micrometer-Registry-Auto-Configuration, die Meter wie jvm.memory.used exposen
Antwort & Erklärung
Richtige Antwort: D
Spring Boot Actuator mit Micrometer auto-konfiguriert eine MeterRegistry, bindet JVM- und System-Metrics und exposed sie via /actuator/metrics und Prometheus-Registry wenn konfiguriert. Das ist der Standard-Observability-Pfad statt ad-hoc Logging oder manueller per-Method-Metrics.
Warum die anderen Optionen falsch sind:
- JSP-Tags sind unrelated zu Micrometer-Metrics in modernen Boot-Apps.
- Logging-Appender ergänzen, ersetzen aber nicht Micrometer-Metrics-Exposure.
- Manuelle per-Method-Metrics sind optional; Boot liefert Registry-Infrastruktur automatisch.
Merksatz: „Boot-Observability: Micrometer-Registry plus Actuator-Metrics und Prometheus-Export."
Weiterlernen: Buchkapitel
Ende von Mock Full 03 — Spring Professional (60 Fragen)