42/60, down from 73%. But the composition of this paper is unlike any before it, and it points at something very specific. Spring Boot went 56% → 86% — the clinic worked within a day, the third time that has happened. Testing collapsed 100% → 33%, the largest single-section fall of the series. And underneath both: 8 of your 18 misses were ticking a class, annotation or method that does not exist in Spring. You need +4. That one habit is worth 8, and it costs no study time at all.
Read the top row and the bottom two together. Spring Boot 56% → 86% — the
Boot clinic went up yesterday and Boot jumped 30 points, with a single
miss. That is now the third clinic to produce an immediate jump (Data 57→75, Boot 56→86). The mechanism
is proven.
And Testing fell 67 points from a section that had held 100% twice running. But look at
what the four Testing misses were: @NoRollback, LOCALE_PORT,
@RunWith(SpringExtension.class) and "Spring mocks RMI". Three of the four are fabricated names —
not decayed knowledge. Testing didn't collapse; the paper happened to test it with invented options and the
habit caught you.
The clock held. 42m 39s, essentially identical to attempt #9's 42m 30s. The slowdown from
29 minutes has stuck across two papers. That was the right change — keep it, and push further.
This is the finding of the paper. Eight separate questions — 44% of your misses — turned on an option naming a class, annotation, method or enum constant that simply is not part of Spring. Not one of them requires knowing the topic to eliminate.
| You ticked | Q | The real thing |
|---|---|---|
| @NoRollback | Q5 | @Commit or @Rollback(false) |
| @NoRollback(true) | Q5 | — same option twice, in two forms |
| @Secure | Sec. | @Secured — one letter |
| @Authorize | Sec. | @PreAuthorize / @PostAuthorize |
| LOCALE_PORT | Q17 | MOCK, RANDOM_PORT, DEFINED_PORT, NONE |
| @ProxyMode("CGLIB") | Q22 | @EnableAspectJAutoProxy(proxyTargetClass = true) |
| @SetProxyMode("CGLIB") | Q22 | — same answer, second invented form |
| JDBCTransactionManager | Q38 | DataSourceTransactionManager |
| JDBCDataSourceTransactionManager | Q38 | — same answer, second invented form |
| @HttpResponseStatus | Q43 | @ResponseStatus |
| DifferentOf | Q46 | Not / IsNot |
| restrict() | Q59 | antMatchers(), mvcMatchers(), regexMatchers() |
Notice the pattern in the pairs. On Q5, Q22 and Q38 you ticked two invented options for the same question. That's the signature of scanning for something that looks plausible rather than asking whether it's real — and on all three, the genuine answer was sitting there unticked.
The running total is now stark. Attempt #7: 7 fakes. #8: 4. #9: 3. #10: 11, across 8 questions. It has been your largest recoverable bucket in four consecutive papers, and this time it is double the gap to a pass.
| Clinic | Published | Section before | Next paper | |
|---|---|---|---|---|
| Data Management | 25 Aug | 57% | 75% | ▲ 18 |
| Data Management (held) | — | 75% | 81% → 82% | holding |
| Spring Boot | 27 Aug | 56% | 86% | ▲ 30 |
Spring Boot went from your worst section to your best in one day, with a single miss — and Actuator, which had cost you marks in four consecutive papers, cost you nothing on this one. Data Management has now held 75–82% across three papers since its clinic. The MVC clinic is the one you haven't drilled yet, and MVC is at 50%.
You asked how to improve your answers to get to the pass mark. This paper gives the least ambiguous answer of the ten:
| Bucket | Marks | What it costs |
|---|---|---|
| ① Names that don't exist Q5, Security fill-in, Q17, Q22, Q38, Q43, Q46, Q59 |
8 | Zero study. One question per option: "have I actually seen this?" |
| ② Facts already on this site Q38 (Data clinic §3), Q46 (Data clinic §8), Q37 + Q43 (MVC clinic), Q47 (#8) |
5 | Drill the three clinics. ~40 minutes, no new material. |
| ③ Spring Core detail Q1, Q14, Q24, Q44, Q48 — scanning, context, bean order, DI, profiles |
5 | Genuine study. Lessons 1–3. |
Bucket ① alone is double the gap. There is no reading, no lesson and no new concept in it. On this paper, eliminating invented options and committing to the survivor would have scored you 50/60 = 83%.
| Section | #6 · 25 am | #7 · 25 pm | #8 · 25 eve | #9 · 26 Aug | #10 · 28 Aug | Verdict |
|---|---|---|---|---|---|---|
| Spring Boot | 40% | 64% | 71% | 56% | 86% | Clinic → best section |
| Data Management | 75% | 57% | 75% | 81% | 82% | Holding since its clinic |
| Spring Core | 57% | 65% | 61% | 75% | 73% | Stable around 73–75 |
| Spring MVC | 67% | 75% | 40% | 57% | 50% | Clinic written, not yet drilled |
| Testing | 70% | 86% | 100% | 100% | 33% | Fell — but on fake names |
| Spring Security | 33% | 100% | 100% | 75% | 33% | Volatile · only 2 misses |
| Overall | 58% | 70% | 70% | 73% | 70% | Flat — but shifting |
@Required".PlatformTransactionManager implementation handles a single JDBC DataSource?"
It is in the Data Management clinic §3, it was a drill you got
wrong on 26 Aug, and I walked you through the naming rule in conversation the same day —
"managers are named after the resource they wrap; nothing in Spring is called JDBC*TransactionManager".
Two days later you ticked JDBCTransactionManager and
JDBCDataSourceTransactionManager. Reading an explanation is not the same as being able to
retrieve it under time pressure — which is what the drills are for, and why this review pushes them so hard.
Your answer is reconstructed from the exported result — if a line looks wrong, tell me and I'll fix it. Purple = an invented name.
| Q | Topic | What you answered | The answer |
|---|---|---|---|
| Q1 | Two configs, two @ComponentScans | Three wrong options ticked | Beans from both packages are registered |
| Q5 | Committing a test transaction | "@NoRollback" + "@NoRollback(true)" — both invented | @Commit · @Rollback(false) |
| Q14 | The ApplicationContext | "It is the front servlet" | Resolves external config · instantiates beans |
| — | Securing service-layer methods | "@Secure, @Authorize" — both invented | @Secured + @PreAuthorize, on methods |
| Q17 | @SpringBootTest webEnvironment | "LOCALE_PORT" — invented | MOCK · RANDOM_PORT · DEFINED_PORT · NONE |
| Q22 | Forcing CGLIB proxies | "@ProxyMode" + "@SetProxyMode" — both invented | @EnableAspectJAutoProxy(proxyTargetClass = true) |
| Q24 | Bean creation order | "on first access" + "reverse order" | The dependency chain, not declaration order |
| Q27 | Micrometer Gauge | "suitable for cumulative metrics" + "updates itself" | A polled snapshot of a value you maintain |
| Q32 | Where Spring provides mock objects | "RMI" | Environment and JNDI |
| Q37 | @RequestMapping statements | Under-selected — missed one of two | Maps all verbs by default · path takes an array |
| Q38 | JDBC transaction manager | Two invented "JDBC…" names — third time | DataSourceTransactionManager |
| Q43 | Mapping an exception to 404 | "@HttpResponseStatus" (invented) + "500" | @ResponseStatus → 404 |
| Q44 | Handling bean dependencies | "@Required" | @Autowired constructor · @Inject · depends-on |
| Q46 | Finder-method keywords | "DifferentOf" — invented | LessThan · Is |
| Q47 | @SpringBootTest's meta-annotation | Both "@RunWith(…)" options | @ExtendWith(SpringExtension.class) |
| Q48 | Maximum active profiles | "2" and "3" | No limit — "none of the above" |
| Q57 | Default template engine | "JSP" + "JSON" | Thymeleaf |
| Q59 | Restricting URLs by pattern | "restrict()" — invented | antMatchers() · mvcMatchers() |
73%, stable. These six are the largest genuine-knowledge cluster on the paper — and now the biggest remaining topic once the fake-name habit is fixed.
@Configuration classes, each with its own @ComponentScanEach @Configuration class is processed independently, and every bean discovered by
any scan lands in one shared ApplicationContext. There is no precedence, no override, no
"first one wins":
@Configuration @ComponentScan("com.example.services") class ServiceConfig {}
@Configuration @ComponentScan("com.example.repositories") class RepositoryConfig {}
// both loaded → beans from BOTH packages available
The distractor worth dismantling is "@ComponentScan must be at the
application entry point". It works on any @Configuration class — the entry point is just
where Boot conventionally puts it, via @SpringBootApplication. Splitting scans across configs is a
legitimate modularisation pattern.
The equivalent single-class form, worth recognising:
@ComponentScan(basePackages = {"com.example.services", "com.example.repositories"}).
ApplicationContext isDispatcherServlet — it uses an ApplicationContext but isn't
one.Its responsibilities, which is what these questions enumerate:
| Does | Via |
|---|---|
| Instantiate and manage bean lifecycles | BeanFactory inheritance |
| Resolve external configuration | EnvironmentCapable + @Value |
| Publish events | ApplicationEventPublisher |
| Resolve i18n messages | MessageSource |
| Load resources | ResourcePatternResolver |
| Create AOP proxies | registered BeanPostProcessors |
The other statement that caught you — "a running application has only one" — is
false because of context hierarchies. Classic Spring MVC has a root context (services,
repositories) and a child servlet context per DispatcherServlet (controllers, view
resolvers). The child can see the parent's beans; the parent cannot see the child's. Spring Boot usually collapses
this into one, but the hierarchy is still supported — and Spring Cloud uses a parent bootstrap context.
@EnableAspectJAutoProxy(proxyTargetClass = true) — it's an attribute, not an annotation@ProxyMode("CGLIB") and @SetProxyMode("CGLIB").
Neither exists. The real mechanism is a boolean on the annotations you already know.The generalisable fact: proxy strategy is a single flag —
proxyTargetClass — exposed by every annotation that sets up an auto-proxy creator:
| Annotation | Plain Spring default | Spring Boot 2.x default |
|---|---|---|
@EnableAspectJAutoProxy | false | true |
@EnableTransactionManagement | false | true |
@EnableCaching | false | true |
@EnableAsync | false | true |
Boot flipped these to true in 2.0 so that injecting by concrete class always
works — with a JDK proxy you can only inject by interface, which surprises people. Note the flag only matters
when the target has an interface; with no interface Spring uses CGLIB regardless.
And a caution: setting it on one annotation does not set it on the others. If both AOP and transactions are in play, set it consistently.
On the invented options: ScopedProxyMode is a real enum — but it's
used on @Scope(proxyMode = …) for scoped beans, not for AOP strategy. That's what makes
@ProxyMode feel familiar: it's a real word from a neighbouring concept.
proxyTargetClass attribute, on every @Enable* that creates proxies. Boot defaults it to true.@Lazy; the second isn't a Spring behaviour at all.Spring resolves the graph and instantiates in dependency order:
beanA → beanB(beanA) → beanC(beanB). Reorder the methods in the file and
nothing changes.
| Mechanism | Effect on order |
|---|---|
| A method parameter (or constructor arg) | the argument bean is created first |
@DependsOn("beanX") | forces beanX first with no injection |
@Lazy | defers creation until first use |
| Declaration order in the file | none |
Why "on first access" is wrong by default: an ApplicationContext
instantiates singletons eagerly at startup — that's one of the things it adds over a bare
BeanFactory, and it's deliberate, so wiring errors surface immediately rather than on first request.
@Lazy opts out per bean.
The companion fact: a circular dependency between constructor-injected singletons throws
BeanCurrentlyInCreationException. Break it with setter injection, @Lazy, or
— better — a redesign.
@Autowired constructor · @Inject · depends-on — not @Required@Required.
It's a real annotation — which makes it a smarter distractor than the invented ones.
But it enforces that a property was set; it doesn't wire anything.| Mechanism | Does | Status |
|---|---|---|
@Autowired | injects by type — constructor, setter or field | the standard |
@Inject (JSR-330) | the same, vendor-neutral | fine |
@Resource (JSR-250) | injects by name | fine |
depends-on / @DependsOn | orders initialisation without injecting | fine |
@Required | asserts a setter was called — no injection | deprecated (Spring 5.1) |
Why @Required was deprecated is the point: constructor injection makes
it unnecessary. If a dependency is a constructor parameter, it cannot be missing — the object can't be
built without it. @Required only ever existed to patch a weakness in setter injection.
Note the shape of this distractor: a real but obsolete annotation. That's the second family
to watch alongside invented names — @Required, WebSecurityConfigurerAdapter,
@MockBean are all real and all superseded.
Profiles are a comma-separated list and Spring imposes no cap:
spring.profiles.active=dev,logging,metrics,eu-west
java -jar app.jar --spring.profiles.active=prod,monitoring
SPRING_PROFILES_ACTIVE=dev,debug
A bean is registered if any of its @Profile values matches an active
profile. Related facts worth carrying: spring.profiles.include adds profiles unconditionally;
spring.profiles.default (default: default) applies when none are active; and
@Profile supports ! for negation.
The technique lesson matters more than the fact here. When the options are small numbers and you don't know a limit exists, "no limit" is usually right — frameworks rarely impose arbitrary caps. And ticking both 2 and 3 guaranteed a zero: they can't both be true, so at least one tick was known to be wrong at the moment you made it.
100% → 33%, but look at the content before concluding it decayed. Three of these four hinge on a fabricated name. The knowledge is largely intact; the filter isn't.
@Commit or @Rollback(false) — both work@NoRollback and @NoRollback(true).
The same invention offered twice, and you took both — while the two genuine answers sat
unticked.Spring's test support rolls back by default, which is the opposite of production. Two ways to override, and they're equivalent:
| Annotation | Effect |
|---|---|
@Commit | commit after the test — semantically explicit |
@Rollback(false) | identical effect |
@Rollback(true) | the default — usually written implicitly |
@Test @Transactional @Commit
void persistsForReal() { … } // survives the test
@Test @Transactional
void rolledBackAutomatically() { … } // the default
Both work at class level or method level, with method beating class. And remember the pairing from
review #7: a rolled-back test never exercises the real commit, so constraint violations that surface only
at flush time can hide — which is exactly when you'd reach for @Commit.
@Commit and @Rollback(false) both flip it. There is no @NoRollback.@SpringBootTest web environments invented constantMOCK · RANDOM_PORT · DEFINED_PORT · NONELOCALE_PORT.
"Locale" is about language and region — it has nothing to do with ports. The word you were
reaching for is "local", and even that isn't one of them.| Value | Server? | Use with |
|---|---|---|
MOCK (default) | no — mock servlet environment | MockMvc |
RANDOM_PORT | yes, random port | TestRestTemplate, WebTestClient |
DEFINED_PORT | yes, the configured port | same |
NONE | no web features at all | plain service tests |
The consequences chain together, and you've met them before: MOCK means no
TestRestTemplate (there's no server to call), and a real port means no
@AutoConfigureMockMvc (MockMvc's whole point is that there's no server).
@LocalServerPort injects whichever port RANDOM_PORT chose.
@SpringBootTest is meta-annotated with taught in #8@ExtendWith(SpringExtension.class) — JUnit 5@RunWith(…) options.
Every option mixed the two frameworks; you had to spot which pairing is coherent.The two ecosystems don't interchange — and each option in that question paired one framework's annotation with the other's class:
| JUnit | Annotation | Spring class |
|---|---|---|
| 4 | @RunWith | SpringRunner (= SpringJUnit4ClassRunner) |
| 5 | @ExtendWith | SpringExtension |
@RunWith(SpringExtension.class) and @ExtendWith(SpringRunner.class) are
both incoherent — a JUnit 4 runner slot given a JUnit 5 extension, and vice versa. Match the version on both
sides and only one option survives.
The practical fact from review #8: since Boot 2.1 the extension is baked into
@SpringBootTest, so writing @ExtendWith yourself is redundant — and
@RunWith on a JUnit 5 class is silently ignored, leaving every @Autowired field
null.
Environment and JNDI — not RMI, not JMXSpring's spring-test module ships mock implementations for a specific, small set of
things — the ones that are awkward to stand up in a unit test:
| Area | Mocks provided |
|---|---|
| Environment | MockEnvironment, MockPropertySource |
| JNDI | SimpleNamingContextBuilder — a fake JNDI tree |
| Servlet API | MockHttpServletRequest/Response, MockHttpSession, MockServletContext |
| Reactive web | MockServerHttpRequest/Response |
| RMI | none |
| JMX | none — you need a real MBeanServer |
The organising idea: Spring mocks the things it abstracts over — the Environment, the Servlet API, JNDI lookups. RMI and JMX are JVM/network facilities Spring merely integrates with; there's no Spring abstraction to substitute.
The servlet mocks are the ones you use constantly without noticing — they're what
MockMvc is built on.
50% — and the MVC clinic is the one clinic you haven't drilled. Two of these three are in it.
@RequestMapping MVC clinic §6path takes an array| Statement | Verdict |
|---|---|
Maps all HTTP methods unless method is set | TRUE — the reason @GetMapping exists |
path/value accept an array of Strings | TRUE — @RequestMapping({"/users","/members"}) |
| Method-level only | false — class and method; it's the only one that does both |
Redundant under @RestController | false — method names are never auto-mapped |
The last distractor is worth a moment: Spring never derives a URL from a method name.
@RestController only means "write the return value to the body" — you still declare every mapping.
That's a different framework's convention (Rails, JAX-RS with some configs), not Spring's.
And the narrowing attributes beyond method: params,
headers, consumes, produces.
@ResponseStatus(HttpStatus.NOT_FOUND) → 404@HttpResponseStatus, 500 and @ResponseStatus,
500. Two errors compounded: an invented annotation, and NOT_FOUND read as 500.HttpStatus.NOT_FOUND is 404 — the enum constant names the status directly.
Worth having the common ones cold, since they appear constantly:
| Constant | Code | Constant | Code |
|---|---|---|---|
OK | 200 | BAD_REQUEST | 400 |
CREATED | 201 | UNAUTHORIZED | 401 |
NO_CONTENT | 204 | FORBIDDEN | 403 |
MOVED_PERMANENTLY | 301 | NOT_FOUND | 404 |
FOUND | 302 | INTERNAL_SERVER_ERROR | 500 |
NOT_MODIFIED | 304 | SERVICE_UNAVAILABLE | 503 |
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Not Found")
public class MyException extends RuntimeException { }
// thrown from a controller → client receives 404
From the MVC clinic: @ResponseStatus works on a handler method or an exception
class, and it overrides status set by other means — including a redirect's default 302. The
programmatic equivalent is ResponseStatusException (Spring 5+), which saves you a class per status.
| Engine | Default? | Starter |
|---|---|---|
| Thymeleaf | yes | spring-boot-starter-thymeleaf |
| FreeMarker | no | spring-boot-starter-freemarker |
| Mustache | no | spring-boot-starter-mustache |
| Groovy Templates | no | spring-boot-starter-groovy-templates |
| JSP | no — actively discouraged | — |
Why Boot pushes away from JSP is the interesting part: JSP doesn't work in an
executable fat jar. It requires a real servlet container with a JSP compiler and an exploded WAR layout, so
java -jar can't serve it. Thymeleaf is plain files on the classpath, which works everywhere — and
its "natural templates" are valid HTML that opens in a browser without a server.
That connects to a fact you already know: fat jars nest dependencies under
BOOT-INF/lib, and JSP's tooling can't see inside them. The template-engine default is a
consequence of the packaging model.
82% — your best Data score of the series, and it has now held 75–82% across three papers since the clinic. Both misses are in that clinic.
DataSourceTransactionManager — named after the resource, not the technologyJDBCTransactionManager and
JDBCDataSourceTransactionManager. Two of the three invented "JDBC…" options
— and you also ticked JDBCPlatformTransactionManager on attempt #8.The rule, one more time, because it generalises: Spring's transaction managers are named after the resource they hold, never after the technology or the interface:
| Holds | Class |
|---|---|
a DataSource | DataSourceTransactionManager |
a JPA EntityManagerFactory | JpaTransactionManager |
a Hibernate SessionFactory | HibernateTransactionManager |
a JTA UserTransaction | JtaTransactionManager |
| an R2DBC connection | R2dbcTransactionManager |
No Spring class in this area starts with JDBC. That single
observation eliminates three of the four options without knowing anything else — which is exactly the check that
would have converted this mark on all three attempts.
Note the option shape too: JDBCPlatformTransactionManager puts the interface
name inside the implementation name. Real Spring implementations don't do that —
DataSourceTransactionManager implements PlatformTransactionManager without saying so.
JDBC*TransactionManager.LessThan and Is — DifferentOf and BiggerThan are inventionsDifferentOf.
You correctly rejected BiggerThan, so the filter was working on one of the two
fakes.The keyword vocabulary is finite and closed — anything outside it throws
PropertyReferenceException at application startup, not at call time:
| Real keyword | SQL | Invented look-alike |
|---|---|---|
Is / Equals | = ? | — |
Not / IsNot | <> ? | DifferentOf |
LessThan / LessThanEqual | < ? / <= ? | SmallerThan |
GreaterThan / GreaterThanEqual | > ? / >= ? | BiggerThan |
Between | BETWEEN ? AND ? | — |
IsNull / IsNotNull | IS [NOT] NULL | IsDifferentNull |
Like, StartingWith, Containing, In, True/False, IgnoreCase, OrderBy… | the rest of the vocabulary | |
The invented ones share a tell: they use everyday comparative English (bigger, smaller, different) where Spring Data uses the terms from SQL and the Comparable API — greater, less, not. If a keyword sounds conversational rather than technical, distrust it.
33% off just two misses — and both were invented names.
@Secured and @PreAuthorize, on methodsThe real method-security family, with the switch each one needs:
| Annotation | Enabled by | SpEL? |
|---|---|---|
@Secured("ROLE_ADMIN") | securedEnabled = true | no — role names only |
@PreAuthorize("hasRole('ADMIN')") | prePostEnabled = true | yes |
@PostAuthorize, @PreFilter, @PostFilter | prePostEnabled = true | yes |
@RolesAllowed (JSR-250) | jsr250Enabled = true | no |
Switched on with @EnableGlobalMethodSecurity(prePostEnabled = true) (Security 5) or
@EnableMethodSecurity (Security 6, where prePostEnabled is on by default).
Worth noting the exam's own caveat: both annotations can go on a class as
well as a method — the "classes" option failed only because of @Secure. So the invented name was
the entire question; the classes-vs-methods distinction was a decoy.
The one-letter trap is the thing to internalise: @Secured, past tense. And the
"authorize" family always carries a position prefix — @PreAuthorize, @PostAuthorize —
never a bare @Authorize.
antMatchers(), mvcMatchers() — and regexMatchers()restrict().
You correctly rejected match(), so one of the two fakes was filtered.| Method | Pattern style | Note |
|---|---|---|
antMatchers("/admin/**") | Ant paths | the classic |
mvcMatchers("/admin") | Spring MVC paths | recommended — matches how MVC itself resolves URLs |
regexMatchers("^/api/v[0-9]+/.*") | regular expressions | for complex cases |
anyRequest() | everything | always last |
Why mvcMatchers is recommended is a real security point:
antMatchers("/admin") matches only that exact string, while Spring MVC would also serve
/admin/, /admin.html and (historically) /admin;jsessionid=…. So an Ant
matcher can leave a route reachable but unprotected. mvcMatchers uses the same matching
Spring MVC uses, closing that gap.
Note the naming convention across all three: every one ends in Matchers.
restrict() and match() both break it — the API describes what it matches on,
not what it does with the result. (In Spring Security 6 these were unified as
requestMatchers(); your exam targets 5.x.)
Matchers. Prefer mvcMatchers: Ant patterns can miss /admin/ and /admin.html.86% — up 30 points, from your worst section to your best, in one day. Actuator, which had cost you marks in four consecutive papers, cost you nothing here. One miss, and it's a fine detail.
Gauge semantics Boot clinic §3 · also #3Counter. You got the other three right.The code in that question makes the mechanism visible — and it's exactly why the distinction matters:
@Bean AtomicInteger gaugeValue() { return new AtomicInteger(0); }
@Bean Gauge customGauge(MeterRegistry reg, AtomicInteger gaugeValue) {
return Gauge.builder("custom.gauge.value", gaugeValue, AtomicInteger::get)
.register(reg); // ← registers a SUPPLIER, not a value
}
// the application must move the value itself:
@GetMapping("/increment")
String increment() { gaugeValue.incrementAndGet(); return "ok"; }
The gauge holds a function, not a number. When the registry is scraped it calls
AtomicInteger::get and reports whatever it finds. It never accumulates, never averages, and does
nothing on its own — which is precisely why the @GetMapping has to increment the
AtomicInteger explicitly.
| Meter | Answers | Who updates it |
|---|---|---|
Gauge | "what is it now?" | you — the gauge just samples |
Counter | "how many so far?" | you call increment(); it accumulates |
Timer | "how long, how often?" | you record; it aggregates |
One trap in the code worth knowing: the gauge holds a weak reference to its source. If the
AtomicInteger were a local rather than a @Bean, it could be garbage collected and the
gauge would report NaN. Declaring it as a bean is what keeps it alive.
proxyTargetClass, an attribute on every @Enable* that creates proxies; Boot defaults it to true@Lazy defers, @DependsOn orders without injecting@Autowired · @Inject · @Resource (by name) · @DependsOn. @Required injects nothing and is deprecated@Profile registers the bean@Commit and @Rollback(false) both flip it. No @NoRollbackwebEnvironment: MOCK (default) · RANDOM_PORT · DEFINED_PORT · NONE. MOCK ⇒ MockMvc; real port ⇒ TestRestTemplate@RunWith + SpringRunner · JUnit 5 = @ExtendWith + SpringExtension; never crossed@RequestMapping maps every verb; path takes an array; it's the only mapping annotation usable at class and method level@ResponseStatus (no "Http" prefix) on a method or exception class; NOT_FOUND = 404DataSourceTransactionManager for JDBC; managers are named after the resource. Nothing is called JDBC*TransactionManagerGreaterThan, LessThan, Not. Not BiggerThan/DifferentOf; bad names fail at startup@Secured (roles) and @PreAuthorize (SpEL) secure methods — no @Secure, no bare @AuthorizeMatchers: antMatchers, mvcMatchers, regexMatchers. Prefer mvcMatchersNaN@NoRollback twice; Q22 offered two ProxyMode spellings; Q38 offered three
JDBC… names. Exam writers pad with variants of a fake to make it look like a family. If two
options differ only in decoration, both are usually wrong and the answer is elsewhere.
(3) Drill the MVC clinic — it's the one you haven't done.
Data and Boot both jumped after theirs; MVC is at 50% and its clinic covers Q37 and Q43 directly.
(4) Keep the clock where it is, then extend it. Two papers at ~42 minutes is real progress from 29. You
still have 87 minutes spare. Target 60+, and spend the extra time on step (1).
(5) Then Spring Core. Five genuine-knowledge marks in
Lessons 1–3 — but you don't need them to pass.
Proven: topic clinics lift a section 18–30 points and it holds — Data 57→75→81→82, Boot 56→86.
Two of three are done, and those are now your two best sections.
Fixed: under-selection (5 marks in #5 → 1 today) and the clock (29 → 42 minutes, held over two papers).
Remaining: one habit worth 8 marks on this paper, one un-drilled clinic, and about five marks of
genuine Spring Core detail.
You have been within 6 marks of the pass on every paper since #7, and this one had 8 free marks in it.
The knowledge is not the constraint any more.