68% on a 60-question mixed set, and the section table tells a single clean story. Spring Boot hit 92% — its best score ever, up from 61% on your last paper. On the very same set, Spring MVC fell from 100% to 57% after two perfect papers, and Data Management fell from 86% to 58%, its worst of the series. Nothing new broke. You stopped drilling them.
| Section | #8 | #9 | #10 | #11 | #12 | this set | |
|---|---|---|---|---|---|---|---|
| Spring Boot | 71% | 56% | 86% | 75% | 61% | 92% | Best ever — the clinic finally landed |
| Spring Core | 61% | 75% | 73% | 58% | 70% | 69% | Flat. Still the only section without a clinic |
| Testing | 100% | 100% | 33% | 60% | 75% | 67% | Clinic built yesterday — not drilled yet |
| Data Management | 75% | 81% | 82% | 86% | 70% | 58% | Worst of the series. Two clinics ago |
| Spring MVC | 40% | 57% | 50% | 100% | 100% | 57% | Straight back to its pre-clinic level |
| Spring Security | 100% | 75% | 33% | 50% | 67% | 57% | Two misses, both one table you already have |
This is the clearest evidence yet for the thing this site has been telling you. Boot was drilled most recently and scored 92%. MVC was drilled three rounds deep, held 100% twice, then went untouched for a week and returned 57% — its exact pre-clinic level. Drilling does not install knowledge permanently; it installs it for about a week. The fix is not another clinic. It is twenty minutes of rotation across all six before you sit.
Not "similar to" — the same table.
Q18 and Q25 are both the filter-chain hierarchy from
master table 2 of the Security clinic, and you got the same class wrong
both times in the same set. Q20 is the PlatformTransactionManager roster from the
Data clinic.
That is three marks — and you are eight short of the pass. There is no new material to learn for those three; there is only retrieval practice you did not do.
| Shape | Count | Where |
|---|---|---|
| Picked a wrong option outright | 8 | Q1, Q2, Q8, Q17, Q18, Q29, the transactional-testing question, Q36 |
| Under-selection — every tick right, stopped early | 2 | Q20, Q25 |
| "All options are correct" questions | 2 | Q20 and Q25 — the ninth and tenth in the series |
| Reached for an API that does not exist | 2 | replaceProdDb (invented) · @TransactionConfiguration (removed in Spring 5.0) |
| Over-selection — ticked an option contradicting three you also ticked | 1 | Q1 |
Q1 is worth staring at. You ticked all three real ways to close a context and "no action is required, Spring closes it automatically". Those cannot both be true — if no action were required, the other three would be pointless. When one option says "nothing is needed" and others describe things you must do, they are mutually exclusive. Tick one side or the other.
ApplicationContextQ1. Three real ways, and the crucial fact that standalone Spring does none of them for you.
| Approach | API | Fires when | Use for |
|---|---|---|---|
| Shutdown hook | ctx.registerShutdownHook() | JVM exits (SIGTERM, System.exit()) | long-running standalone apps |
| Explicit close | ctx.close() | immediately | CLI tools, deterministic teardown |
| try-with-resources | try (var ctx = ...) { } | the block exits | tests, short scripts |
| Nothing at all | — | never | your answer — no destroy callbacks run |
The one fact behind all four rows:
AbstractApplicationContext does not register a JVM shutdown hook by itself. Spring Boot's
SpringApplication.run(...) calls registerShutdownHook() for you — which is exactly why
this feels wrong. Boot spoils you; raw standalone code must opt in.
try-with-resources works because
ConfigurableApplicationContext extends Closeable, which extends
AutoCloseable. And two traps: kill -9 bypasses every JVM shutdown hook (nothing
is destroyed), and prototype beans never get destroy callbacks no matter how you close — the container
does not track them.
Q18 and Q25. This is a reprint of the Security clinic's table because it has now caught you in four consecutive sittings.
Servlet container
│
▼
DelegatingFilterProxy a SERVLET filter — the bridge into Spring
│ (registered with the container; delegates to a bean)
▼
FilterChainProxy a Spring BEAN that is itself a Filter
│ (matches the request to a chain by URL pattern)
├─► SecurityFilterChain /api/** [filters...]
└─► SecurityFilterChain /** [filters...]
│
▼
the individual security filters
| Name | What it is | The keyword that identifies it |
|---|---|---|
DelegatingFilterProxy | a Servlet filter registered with the container | "bridges the container and the Spring context" |
FilterChainProxy | a Spring bean that implements Filter and routes to chains | "delegates to a list of filter beans", "URL patterns" |
SecurityFilterChain | an interface — a chain matched against a request. Never the intercepting filter. | "interface", "matched against an HttpServletRequest" |
DelegatingProxy | Does not exist. You correctly rejected it — good. | |
On Q18 you answered SecurityFilterChain, which
is the one name in the list that is never a filter. It is an interface describing a chain. Both
proxies implement Filter; the chain does not.
Note on Q18's marking: the bank accepts both
FilterChainProxy and DelegatingFilterProxy. If you are ever forced to pick one:
DelegatingFilterProxy is the filter the Servlet container knows about;
FilterChainProxy is the Spring bean that does the actual security work. Both are Filters, so
a stem saying "intercepts all requests" fits either.
@-prefixedQ29. There are two parallel families, and the @ version asks a different question
from the plain one.
| Designator | Matches on | Plain-vs-@ pair |
|---|---|---|
@annotation(A) | the executed method carries @A | — |
@args(A) | the runtime class of each argument carries @A | args(Type) matches argument types |
@within(A) | the declaring type of the join point carries @A | within(Type) scopes to a type or package |
@target(A) | the runtime class of the target object carries @A | target(Type) matches the target's type |
execution(...) | a method signature | the workhorse — no @ form |
bean(name) | the Spring bean name — Spring-only, not AspectJ | no @ form |
One sentence for the whole table: the
@ tells you an annotation is involved; the word after it tells you WHERE the annotation
sits — on the method (@annotation), on the arguments (@args), on the declaring
class (@within), on the target object's class (@target).
Q29's stem said "whose argument types carry a specified
annotation". The word argument points at exactly one row. You answered
@annotation, which is the method row.
And remember: @args needs RetentionPolicy.RUNTIME — a source-retained
annotation is invisible to the proxy.
PlatformTransactionManager implementationsQ20 asked which transaction APIs Spring supports through the abstraction. All four options were correct and you ticked fewer.
| Implementation | Underlying API | Use when |
|---|---|---|
DataSourceTransactionManager | plain JDBC — Spring's own | JdbcTemplate, no ORM |
JpaTransactionManager | JPA | Hibernate-as-JPA, EclipseLink — auto-configured by Boot |
HibernateTransactionManager | Hibernate native API (spring-orm) | native Session, not JPA |
JtaTransactionManager | JTA | distributed / global transactions across resources |
R2dbcTransactionManager | reactive R2DBC | reactive stacks (Boot 3) |
The point of the abstraction is that the answer is always
"yes". PlatformTransactionManager exposes getTransaction(),
commit() and rollback(), and every persistence technology gets an implementation
behind that interface — which is why @Transactional works identically over all of them.
If a question asks "which of these does Spring support through PlatformTransactionManager",
tick everything that is a real persistence API.
One genuine trap for elsewhere: with JPA in play, use
JpaTransactionManager — a JdbcTemplate then joins the same transaction. Adding
DataSourceTransactionManager alongside JPA gives you two managers on two connections that do
not share a transaction.
ApplicationContext in a standalone application over-selectionSpringApplication.run(...) registers the hook on your behalf. Raw
standalone code gets nothing.See master table 1 for the three real approaches. What actually happens when you skip them: the
JVM terminates, and @PreDestroy methods and DisposableBean.destroy() are
silently never called.
// opt in explicitly — long-running standalone app
ConfigurableApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
ctx.registerShutdownHook();
// or let the block close it — tests and short tools
try (ConfigurableApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class)) {
ctx.getBean(MyService.class).run();
} // close() called here
@Bean methods@Bean(name = {...}) takes an array — a bean can have several namesname property can specify only a single
name". It is an array attribute. The extra entries become aliases for the same singleton
instance.The four facts this question rotates through:
| Statement | Why | |
|---|---|---|
| No attributes ⇒ the bean is named after the method | TRUE | the default naming strategy |
name takes only one name | FALSE | it is String[] — extras are aliases |
@Bean inside @Configuration creates beans | TRUE | and gets CGLIB proxying, so inter-method calls return the singleton |
@Bean has a scope attribute | FALSE | use @Scope alongside it |
@Bean(name = {"primaryBean", "secondaryBean"}) // one bean, two names
public MyBean namedBean() { return new MyBean(); }
@Bean
@Scope("prototype") // scope is a SEPARATE annotation
public MyBean prototypeBean() { return new MyBean(); }
@Bean attributes are name/value,
autowire (deprecated), initMethod, destroyMethod. No
scope. And @Bean outside @Configuration (in a plain
@Component) still creates beans — but in "lite" mode, with no proxying and no singleton guarantee
on direct calls.Both misses are master table 2, and it is already on this site.
DelegatingFilterProxy and FilterChainProxy — never SecurityFilterChainSecurityFilterChain. It is an
interface representing a chain of filters. It is not itself a filter and intercepts nothing.See master table 2 for the hierarchy. You did correctly reject the invented
DelegatingProxy, which is the trap this question usually leads with.
FilterChainProxy? under-selection · all correctFilter interface, and that it matches
URL patterns to chains — are equally true.All three properties of FilterChainProxy, which is why "All of the above" wins:
javax.servlet.Filter — it really is a filter, not just a holderSecurityFilterChain instances@DataJpaTest swapping in an embedded database invented API@AutoConfigureTestDatabase(replace = Replace.NONE)@DataJpaTest(replaceProdDb = Replace.NONE).
There is no such attribute — that would not compile. @DataJpaTest has no
database-replacement attribute at all.@DataJpaTest is meta-annotated with
@AutoConfigureTestDatabase(replace = Replace.ANY). You override it by putting your own
@AutoConfigureTestDatabase on the test class:
Replace mode | Behaviour |
|---|---|
ANY (the default) | replace any DataSource — auto-configured or one you declared |
AUTO_CONFIGURED | replace only the auto-configured DataSource |
NONE | do not replace — keep the configured DataSource |
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE) // keep the real database
class UserRepositoryIT { }
@AutoConfigure* annotation is a separate annotation you
stack on the test — never an attribute of the slice. And note the trap in the explanation: putting an
embedded DB on the classpath does not keep the real one. Replace.ANY wins regardless.@TransactionConfiguration does not exist in Spring 5.3 — your exam's version@TransactionConfiguration annotation." Deprecated in Spring 4.2 and
removed entirely in Spring 5.0. It was real once, which is why it feels familiar.How you actually name a transaction manager in a test now, plus the three neighbouring facts:
| Statement | Why | |
|---|---|---|
Set the manager via @TransactionConfiguration | FALSE | removed in Spring 5.0 — use @Transactional("myTxManager") |
@Before / @BeforeEach runs outside the test transaction | FALSE | it runs inside it |
The test rolls back a REQUIRES_NEW service transaction | FALSE | REQUIRES_NEW is independent and commits on its own |
@Rollback with defaults rolls back after the method | TRUE | @Rollback defaults to true |
REQUIRES_NEW escapes the test's rollback. That is the single
most useful fact here — it is also why a service using REQUIRES_NEW leaves rows behind after a
"rolled back" test. Use @Commit or @Rollback(false) when you want the data
kept.PlatformTransactionManager support? all four correctSee master table 4. The mental model that makes guessing unnecessary: the whole purpose of the abstraction is that every persistence technology gets an implementation behind it. There is no mainstream Java transaction API that Spring leaves out.
DataSourceTransactionManager is "Spring's own transaction
management" — plain JDBC, no ORM. If that phrase appears as an option next to JPA/JTA/Hibernate, it is the
JDBC one, and it is true.@args — the word after the @ tells you where the annotation sits@annotation. That matches when the
executed method carries the annotation, not when the argument's class does.See master table 3 for the full grid. The four @-designators as one sentence each:
@annotation(A) — the method is annotated@args(A) — the arguments' runtime classes are annotated@within(A) — the declaring class is annotated@target(A) — the target object's runtime class is annotated@Before("execution(* com.app..*(..)) && @args(com.app.Sensitive)")
public void redact(JoinPoint jp) { }
// matches: service.save(new SsnDto()) // SsnDto is @Sensitive
// does not: service.save("plain string")
args(Type) filters by argument type; @args(Ann)
filters by an annotation on the argument's class. One character, completely different question. And
bean(name) is Spring-only — it is not AspectJ at all.Only one miss, but the section fell from 100% to 57% — the other misses were spread across topics the export did not detail. This one is the most basic pair in the section.
@RequestBody — you answered @ResponseBody, which is the opposite direction@ResponseBody. That serialises the method's
return value into the response. The stem asked about reading the request.Both use an HttpMessageConverter; they differ only in direction.
| Annotation | Direction | Sits on |
|---|---|---|
@RequestBody | request → object (deserialise, incoming) | a method parameter |
@ResponseBody | object → response (serialise, outgoing) | the method or the class |
@RequestMapping | routing only — no body handling | method or class |
@RequestMethod | Not an annotation. RequestMethod is an enum used as @RequestMapping(method = RequestMethod.POST). | |
@RequestBody touches the request body; @ResponseBody touches the response body.
It sits on a parameter for incoming, on the method for outgoing — the position alone tells you
which one a code snippet is using.schema.sql and data.sql
only for embedded databases — H2, HSQLDB, Derby. Pointing at a real Postgres and expecting the
scripts to run is the classic production surprise.The four statements, ruled individually:
| Statement | Detail | |
|---|---|---|
| Initialises in-memory and real databases | FALSE | embedded only, unless you opt in |
Loads schema.sql (DDL) and data.sql (DML) | TRUE | from the classpath root |
| A failing script still lets the app start | FALSE | fail-fast — startup aborts |
Loads schema-${platform}.sql / data-${platform}.sql | TRUE | driven by spring.datasource.platform |
# turn initialization on for a real database (Boot 2.5+)
spring.sql.init.mode=always
# Boot 2.4 and earlier:
spring.datasource.initialization-mode=always
spring.datasource.platform=mysql # also loads schema-mysql.sql, data-mysql.sql
Ten misses, thirty-six drills. Run them now, then run them again in three days — that gap is the whole lesson of this set.
registerShutdownHook(), close() or try-with-resources — Boot is what registers the hook automatically@Bean(name = {...}) takes an array; there is no scope attribute (use @Scope); no attributes means the bean is named after the method@RequestBody reads the request onto a parameter; @ResponseBody writes the return value to the response. @RequestMethod is not an annotation — RequestMethod is an enumDelegatingFilterProxy bridges the container · FilterChainProxy routes by URL · SecurityFilterChain is an interface, never the filterFilterChainProxy is all three things at once — a Filter, a chain manager, and a URL matcher. On that question, "All of the above"@AutoConfigureTestDatabase(replace = Replace.NONE) keeps the real DataSource. @DataJpaTest has no replacement attribute of its own; its default is Replace.ANY@TransactionConfiguration was removed in Spring 5.0. Use @Transactional("txManagerName"). @Rollback defaults to true; @BeforeEach runs inside the transaction; REQUIRES_NEW escapes the rollbackPlatformTransactionManager covers JDBC, JPA, Hibernate native and JTA — if the option is a real persistence API, it is true@ names the position: @annotation = method · @args = arguments · @within = declaring class · @target = runtime class. bean() is Spring-onlyschema.sql = DDL, data.sql = DML; a failing script stops startup; spring.datasource.platform adds -${platform} variants