You scored 42 / 60 = 70%, up from 35/60 this morning. That is the largest single-day gain in the series, and it happened without any new material — you read review #6 and re-sat. Five of the six sections went up. Spring Security went from 33% to 100% with zero misses. Pass is 76% (46/60), so you need +4 — the closest you have been since attempt #4. Two things now stand between you and the pass, and neither is broad: AOP is 5 of your 18 misses, hidden inside a "Spring Core 65%" that looks unremarkable, and you are still ticking two or three options on single-answer questions — that alone was 8 marks.
Every section review #6 targeted went up, within hours. Security 33 → 100 (its three misses
in the morning paper were the exact material in review #6's Security section), Boot 40 → 64, Testing
70 → 86. There is now no argument left about whether the reviews work.
And the one that fell is the one you stopped rehearsing. Data Management went 75 → 57. It
was your best section this morning because review #5 had rebuilt it — six days later it decayed, you
rebuilt it, and one attempt after that it is sliding again. You are rotating knowledge in and out, not
accumulating it.
The clock, seventh attempt running — and now going the wrong way. 40m 10s of 2h 10m: 31%
of your time, 90 minutes unused, 40 seconds per question. You were faster today than yesterday
(49 min), which was faster than the day before (45 min). This is the one habit that has never once moved.
Q3, Q8, Q23, Q26 and Q39 are all Aspect-Oriented Programming, and the score report buries them inside "Spring Core 65%" — a number that looks merely mediocre. Strip AOP out and the rest of Core is running at roughly 80%. AOP alone is worth more than the four marks you need. It is also the most self-contained topic on the syllabus: five advice types, four annotation designators, one proxy model. Lesson 7 plus the five explanations below is a single evening's work, and it closes the gap on its own.
The last two columns are the same day, four hours apart, with review #6 read in between.
| Section | #4 · 18 Aug | #5 · 19 Aug | #6 · 25 Aug am | #7 · 25 Aug pm | Verdict |
|---|---|---|---|---|---|
| Spring Security | 100% | 60% | 33% | 100% | Fixed on demand, twice |
| Testing | 73% | 88% | 70% | 86% | Reliably strong |
| Spring MVC | 57% | 67% | 67% | 75% | Best MVC score yet |
| Spring Core | 62% | 71% | 57% | 65% | Never above 71 — AOP is the drag |
| Spring Boot | 78% | 92% | 40% | 64% | Recovering, not yet back |
| Data Management | 91% | 36% | 75% | 57% | Most volatile of all — 4 swings in 4 papers |
| Overall | 72% | 70% | 58% | 70% | — |
/bootactuator and /endpoint/actuator — two
invented paths — while /actuator sat there unticked. On Q2, Q26 and Q39 you ticked three wrong
options each.banner.properties, META-INF/config,
TransactionExecutor), absolutes ("@Autowired is necessary", "@PostConstruct can
take parameters"), and one design opinion./bootactuator, /endpoint/actuator,
banner.properties, META-INF/boot, META-INF/config and
TransactionExecutor. That is more than the four marks you need, from two habits.ProductRepository code, the same five options about EmptyResultDataAccessException.
This morning you under-selected. Review #6 spelled out the fix — "the only false statement was the
opinion one: the method should throw a custom exception instead of returning null". This afternoon you ticked
exactly that option. The same question, the written answer in front of you hours earlier, missed in the
opposite direction. Reading a review is not the same as rehearsing it. Do the drills, don't just read the
prose.
Your answer is reconstructed from the exported result — if a line looks wrong, tell me and I'll fix it. Click the topic to jump to the full explanation.
| Q | Topic | What you answered | The answer |
|---|---|---|---|
| Q2 | Custom stereotype annotation | Three wrong options ticked (new scope · transactional · replaces @Service) | It registers the class as a bean, plus custom metadata |
| Q3 | @annotation pointcut | "Triggered even if @Transactional is on a parent class method" | Matches only methods directly annotated |
| Q8 | Valid cross-cutting concerns | Under-selected — missed one of the three | Transactions · Security · Tracing (not File or Network I/O) |
| Q10 | Custom RestTemplate headers | "application.properties" + "set them on the RestTemplate instance" | Pass an HttpEntity carrying HttpHeaders |
| Q12 | Custom Boot banner | "Rename application.properties to banner.properties" | banner.txt in resources · the Banner interface |
| Q17 | EmptyResultDataAccessException | "Should throw a custom exception instead of returning null" | The other four — same question as #6's Q47 |
| Q23 | Advice taking (JoinPoint, Exception) | "Before" + "After Returning" | @AfterThrowing, binding via throwing= |
| Q24 | Default Actuator URL | "/bootactuator" + "/endpoint/actuator" — both invented | http://localhost:8080/actuator |
| Q26 | Matching an annotated argument type | "args" + "bean" + "within" | @args |
| Q27 | @PostConstruct / @PreDestroy constraints | "Can take parameters" | Must return void · must take no parameters |
| Q33 | Location of spring.factories | "WEB-INF/" + "META-INF/config/" | META-INF/spring.factories |
| Q37 | Programmatic transaction management | "TransactionExecutor" + "@Transactional" | TransactionTemplate |
| Q38 | Externalising configuration | "XML files" | YAML · properties · environment variables |
| Q39 | Advice that can commit or roll back | "@AfterReturning" + "@Before" + "@AfterThrowing" | @Around — the only one that wraps the call |
| Q41 | @Transactional on a test class | "Moving it to testA() gives the same behaviour" | Own transaction per method · rolled back · @Commit overrides |
| Q48 | Constructor injection | "@Autowired is necessary to inject dependencies" | Optional since Spring 4.3 for a single constructor |
| Q51 | Pooling DataSources | Under-selected — missed one of the three | HikariCP · DBCP2 BasicDataSource · C3P0 ComboPooledDataSource |
| Q53 | Valid SpEL expressions | "(() => 2 * 3)()" — JavaScript, not SpEL | T() · projection ![] · selection ?[] · method calls |
This is the section that decides your next attempt. Five marks, one topic, and the whole topic is three small tables: the five advice types, the pointcut designators, and the proxy model. Learn these five explanations and you have your +4 with a mark to spare.
@Around — the only advice that wraps the callThink of the five advice types as positions around the target call, and it becomes obvious that only one of them can own both sides:
| Advice | Runs | Sees the outcome? | Can replace / skip the call? |
|---|---|---|---|
@Before | before only | no | no |
@AfterReturning | after normal return | the return value | no |
@AfterThrowing | after a throw | the exception | no |
@After | after, always (a finally) | no — can't tell which happened | no |
@Around | both sides | both | yes |
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object tx(ProceedingJoinPoint pjp) throws Throwable {
TransactionStatus status = txManager.getTransaction(definition);
try {
Object out = pjp.proceed(); // run the target
txManager.commit(status); // normal return → commit
return out;
} catch (Throwable t) {
txManager.rollback(status); // threw → roll back
throw t; // re-throw, or you hide the failure
}
}
This is how Spring does it. @Transactional is implemented by
TransactionInterceptor, an @Around-style MethodInterceptor — which is also
why @Transactional is silently ignored on private methods and why self-invocation bypasses it.
Making that connection turns four separate exam facts into one.
(JoinPoint, Exception) advice types · taught in #5@AfterThrowing — the Exception parameter is the giveaway@Before
runs when nothing has been thrown yet, and @AfterReturning runs only when nothing was thrown at
all.Read advice questions off the parameter list — each advice type binds a different second parameter, and that mapping is one-to-one:
| Signature | Advice | Bound by |
|---|---|---|
(JoinPoint) | any of the four non-around types | — |
(JoinPoint, Exception ex) | @AfterThrowing | throwing = "ex" |
(JoinPoint, Object result) | @AfterReturning | returning = "result" |
(ProceedingJoinPoint pjp) | @Around | required, always first |
@AfterThrowing(pointcut = "execution(* com.example..*Repository.*(..))",
throwing = "ex")
public void onFailure(JoinPoint jp, DataAccessException ex) { … }
Three facts that ride with it. The declared type filters: narrow the parameter to
DataAccessException and the advice only fires for those — the exception still propagates either way.
@AfterThrowing never swallows; only @Around with a try/catch can
suppress or substitute an exception. And JoinPoint must be first if declared, with the bound
parameter after it.
Exception parameter ⇒ @AfterThrowing + throwing=. A result parameter ⇒ @AfterReturning + returning=.@args — the @ prefix means "annotated with", every timeThe designators come in pairs, and the @ is the whole distinction: without it you match
on types and names, with it you match on annotations. Learn the table as four pairs:
| Designator | Matches on | Example |
|---|---|---|
execution(…) | a method signature pattern | execution(* com.app.service.*.*(..)) |
within(…) | any join point inside a type or package | within(com.app.service..*) |
@within(Ann) | types annotated with Ann (declaring class) | @within(org.springframework.stereotype.Service) |
args(Type…) | the runtime types of the arguments | args(String, int) |
@args(Ann) | the argument's runtime class is annotated with Ann | @args(com.app.Validated) |
@annotation(Ann) | the executing method carries Ann | @annotation(Transactional) |
@target(Ann) | the runtime class of the target object carries Ann | @target(Repository) |
target(Type) / this(Type) | target object type / proxy type | this(com.app.Marker) |
bean(name) | the Spring bean name | bean(*Service) |
The pitfall the exam likes: @args inspects the runtime class of the argument passed
in, not the declared parameter type — so if a subclass is passed and only the superclass carries the
annotation, it does not match. bean(…) is Spring-only (not AspectJ) and is the one designator
that has nothing to do with types at all.
@ = match a type or name. With @ = match an annotation. args→@args, within→@within, target→@target.@annotation(Transactional) matches taught in #5@annotation.Three separate boundaries, all of which this question tested at once:
| Where the annotation is | @annotation(X) matches? | What would match |
|---|---|---|
| On the executing method | yes | — |
| On the class | no | @within(X) or @target(X) |
| On a parent class's method (overridden here) | no | annotate the override, or use @within |
| On an interface method | no | annotate the implementation |
This is worth understanding rather than memorising, because it explains a real Spring behaviour:
Java does not inherit method annotations (only @Inherited class annotations are
inherited, and even then not through interfaces). It is exactly why Spring's own
@Transactional resolution uses AnnotatedElementUtils to search up the hierarchy
explicitly rather than relying on the JVM — and why documentation warns that putting
@Transactional on an interface method is fragile.
The test is one question: would this code look the same in a completely unrelated module? If yes, it's cross-cutting. If it exists because of what this particular class is for, it's domain.
| Concern | Cross-cutting? | Why |
|---|---|---|
| Transactions | yes | begin/commit/rollback is identical in every service — the reason @Transactional exists |
| Security | yes | the same authorisation check on hundreds of methods; Spring Security applies it by method interception |
| Tracing | yes | span start/end and correlation IDs, owned by no layer |
| Logging · caching · retry · metrics | yes | the rest of the canonical list |
| File I/O | no | if a class reads files, that is its job — logging about it would be cross-cutting |
| Network I/O | no | same reasoning; the retry/circuit-breaker around it is cross-cutting |
The trap in both wrong options is the same move: naming the subject of a cross-cutting concern rather than the concern. And note the related distinction the exam sometimes tests — shared code is not automatically a cross-cutting concern. A utility method called from everywhere is just code reuse; it becomes cross-cutting only when it must be applied around many unrelated methods.
40% → 64% after review #6 — real progress, not yet finished. Three of these four are "where does the file live / what is the path", which is pure recall.
http://localhost:8080/actuatorReview #6 covered the property; this question just asks for its default value:
| Property | Default | Result |
|---|---|---|
management.endpoints.web.base-path | /actuator | /actuator/health |
set to /manage | — | /manage/health |
management.server.port | the app port | moves Actuator to its own port |
And remember the exposure rule that goes with it, because they are often asked together:
GET /actuator returns a discovery document listing exposed endpoints — which by default is
only health over HTTP. Every other endpoint exists but is invisible until you add it to
management.endpoints.web.exposure.include.
/actuator. Nothing prefixed with "boot", nothing nested under "endpoint".spring.factories livesMETA-INF/spring.factories — at the root of META-INF, no sub-folderWEB-INF isn't even on the classpath in the sense
SpringFactoriesLoader means.SpringFactoriesLoader scans every JAR on the classpath for exactly
META-INF/spring.factories and merges what it finds. Keys are interface names, values are
comma-separated implementation names:
# META-INF/spring.factories
org.springframework.context.ApplicationListener=\
com.example.MyListener,\
com.example.OtherListener
| Key | Registers |
|---|---|
EnableAutoConfiguration | auto-configuration classes (legacy — see below) |
ApplicationContextInitializer | pre-refresh context customisation |
ApplicationListener | listeners registered before refresh |
EnvironmentPostProcessor | mutating the Environment very early |
FailureAnalyzer | turning exceptions into readable startup diagnostics |
The version fact worth knowing: Boot 2.7 deprecated registering auto-configurations
under the EnableAutoConfiguration key, moving them to
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (one class per line)
alongside the @AutoConfiguration annotation; Boot 3 removed the legacy key entirely. All the
other keys still live in spring.factories. The whole mechanism runs
before the ApplicationContext exists, which is why it's a file and not a bean.
META-INF/spring.factories — root of META-INF. Auto-config moved to META-INF/spring/…AutoConfiguration.imports in Boot 2.7+.banner.txt in src/main/resources, or implement BannerExactly two supported routes, plus the properties that control them:
| Route | How |
|---|---|
| Static file | src/main/resources/banner.txt — auto-detected |
| Programmatic | app.setBanner((env, cls, out) -> out.println("…")) before run() |
| Move the file | spring.banner.location=classpath:my-banner.txt |
| Turn it off | spring.main.banner-mode=off (also console, log) |
SpringApplication app = new SpringApplication(MyApp.class);
app.setBanner((environment, sourceClass, out) -> out.println("=== My Application ==="));
app.run(args);
banner.txt supports placeholders — ${spring-boot.version},
${application.version}, ${application.title} (the last two come from
MANIFEST.MF, so they're empty when you run from an IDE) — and ANSI colour codes such as
${AnsiColor.BRIGHT_YELLOW}. There is no spring.banner.text property: you can point
at a file, but you can't inline the content.
banner.txt) or a class (Banner). spring.banner.location moves it, spring.main.banner-mode=off kills it.The sources, and the order in which later ones win — the precedence list is itself a stock question:
| Priority | Source | Example |
|---|---|---|
| highest | command-line arguments | --server.port=8081 |
| ↑ | OS environment variables | SPRING_DATASOURCE_URL=… |
| ↑ | Java system properties | -Dserver.port=8081 |
| ↑ | profile-specific files | application-prod.yml |
| lowest | application.properties / application.yml | packaged defaults |
Two details that get tested. Relaxed binding is what makes environment variables work:
SPRING_DATASOURCE_URL, spring.datasource.url and spring.datasource.URL all
bind to the same property, because Boot normalises case, hyphens and underscores. And
@Value vs @ConfigurationProperties: the first pulls one value, the second binds a
whole prefix to a typed object and supports validation and relaxed binding properly.
These four plus the five AOP misses are what produced "Core 65%". On their own they'd be about 80% — the container fundamentals are in better shape than the headline suggests.
@ServiceSpring resolves annotations transitively, so anything meta-annotated with
@Component — directly or through @Service/@Repository/@Controller
— is picked up by component scanning:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service // ← this is what makes it a bean
public @interface SpecialService {
String description() default "Special service layer";
}
@SpecialService(description = "Handles special business logic")
public class SpecialOrderService { } // registered, singleton, name "specialOrderService"
| Claim | Verdict | Why |
|---|---|---|
| Registers the bean, description is metadata | TRUE | meta-annotation inheritance |
| Defines a new scope | false | scope comes from @Scope; default stays singleton |
| Makes it transactional | false | that needs @Transactional |
| Documentation only | false | RUNTIME retention + @Service means it's active |
Replaces @Service | false | it uses @Service; both remain available |
Two mechanics behind it: @Retention(RUNTIME) is mandatory (Spring reads annotations
reflectively at runtime), and this is the same technique Spring itself uses — @RestController is
just @Controller + @ResponseBody, @SpringBootApplication is three
annotations. You can also use @AliasFor to expose an attribute of the meta-annotation, e.g. letting
your annotation set the bean name.
void return, no parameters — but any visibilityThe full contract, which is small enough to memorise outright:
| Constraint | Rule |
|---|---|
| Return type | must be void |
| Parameters | must take none |
| Visibility | any — public, protected, package-private or private |
static | must not be static |
| Exceptions | may throw unchecked; a checked exception is not allowed on @PreDestroy |
| How many | one per class by convention (inherited ones also run) |
Place them in the lifecycle to make the constraints obvious: @PostConstruct runs
after all dependency injection is complete but before the bean is handed out, which is precisely why it
takes no arguments — everything it needs is already injected into fields. @PreDestroy runs on context
close, and never runs for prototype-scoped beans, which Spring does not track after creation.
The three equivalent mechanisms, in the order Spring invokes them:
1. @PostConstruct · 2. InitializingBean.afterPropertiesSet() ·
3. @Bean(initMethod = "…"). Destruction mirrors it:
@PreDestroy → DisposableBean.destroy() → destroyMethod.
@Autowired necessary?@Resource/@Inject are alternatives.The rule and its boundary:
@Controller
public class MyController {
private final MyService myService;
public MyController(MyService myService) { // only constructor → @Autowired implied
this.myService = myService;
}
}
| Situation | Need @Autowired? |
|---|---|
| Exactly one constructor | no (Spring 4.3+) |
| Two or more constructors | yes — mark the one to use |
| Setter or field injection | yes (or @Resource / @Inject) |
The other correct option is worth learning as its own fact — how Spring breaks a tie when
several beans match a type: @Qualifier narrows the candidates, then @Primary wins among
what remains, then @Priority, and finally Spring matches the injection-point name (the field or
constructor-parameter name) against the bean names. Only if none of that resolves it do you get
NoUniqueBeanDefinitionException. That last fallback is why a parameter called
myService quietly matches a bean named myService.
T(), projection ![], selection ?[], method calls — the arrow function was JavaScript(() => 2 * 3)(). SpEL has no
lambda or arrow-function syntax at all. Recognising the language a snippet is written in is a valid
elimination.The SpEL operators worth recognising on sight:
| Syntax | Name | Does |
|---|---|---|
T(java.util.Date) | type reference | reach statics: T(java.lang.Math).PI |
list.![expr] | projection | map each element → new collection |
list.?[pred] | selection | filter the collection |
list.^[pred] / list.$[pred] | first / last match | single element |
#this, #root | context variables | current element / root object |
obj?.field | safe navigation | null instead of NPE |
a ?: b | Elvis | default when null |
isMember('x') | method invocation | calls a method on the root object |
The distinction most often tested: #{…} is SpEL, evaluated by
SpelExpressionParser; ${…} is a property placeholder, resolved by
PropertySourcesPlaceholderConfigurer. They look alike, are processed by different machinery, and
@Value("#{T(java.lang.Math).PI}") vs @Value("${server.port}") is the classic pairing.
Remember ! = map, ? = filter — the projection/selection pair is the one people mix up.
#{} is SpEL, ${} is a placeholder. ![] maps, ?[] filters, T() reaches statics.75% → 57% — the only section that fell. It has now swung 91 → 36 → 75 → 57 across four papers, which makes it the single strongest argument for covering every section every time rather than chasing the worst one.
The transferable lesson first: when an option says a method should be
written differently, it is expressing a preference, not a fact about Spring. The exam asks what the framework
does. Returning null after catching the exception is a legitimate design choice, so
"should throw instead" cannot be correct.
JdbcTemplate call | 0 rows | 1 row | >1 row |
|---|---|---|---|
queryForObject(…) | EmptyResultDataAccessException | the object | IncorrectResultSizeDataAccessException |
query(…) / queryForList(…) | empty List | 1 element | n elements |
Hierarchy: EmptyResultDataAccessException →
IncorrectResultSizeDataAccessException → DataAccessException →
RuntimeException. Because it is a distinct subclass you can catch "no rows" precisely without
swallowing connection failures or constraint violations — and because the whole hierarchy is
unchecked and technology-neutral, the same catch blocks work for JDBC, JPA and Hibernate.
TransactionTemplateSpring gives you two transaction styles, and the exam wants you to name the class for each:
| Style | Mechanism | When |
|---|---|---|
| Declarative | @Transactional + an AOP proxy | almost always |
| Programmatic | TransactionTemplate | fine-grained control, conditional rollback, part of a method |
| Programmatic, low-level | PlatformTransactionManager + TransactionStatus directly | rarely — you manage commit/rollback by hand |
txTemplate.execute(status -> {
accountDao.debit(from, amount);
accountDao.credit(to, amount);
if (somethingIsOff) status.setRollbackOnly(); // conditional rollback
return null;
});
Keep the type names straight, because they are exactly what gets swapped in distractors:
TransactionManager is the empty marker interface;
PlatformTransactionManager is the real synchronous one (its implementations are
DataSourceTransactionManager, JpaTransactionManager,
JtaTransactionManager); ReactiveTransactionManager is the reactive sibling.
TransactionTemplate is built on a PlatformTransactionManager and follows the
same template-callback pattern as JdbcTemplate. Use
TransactionCallbackWithoutResult when there's nothing to return.
BasicDataSource, C3P0 ComboPooledDataSourceDatabaseConnectionFactory (invented) and
SingleConnectionDataSource (one connection is the opposite of a pool).Split the implementations into pools and non-pools, because that's the only distinction the question ever draws:
| Implementation | Pooled | Use |
|---|---|---|
HikariDataSource (HikariCP) | yes | Boot's default since 2.0 |
org.apache.tomcat.jdbc.pool.DataSource | yes | legacy Tomcat deployments |
BasicDataSource (DBCP2) | yes | Commons DBCP environments |
ComboPooledDataSource (C3P0) | yes | legacy C3P0 setups |
DriverManagerDataSource | no | opens a fresh connection every call — tests only |
SingleConnectionDataSource | no | one physical connection, reused |
SimpleDriverDataSource | no | uses a Driver instance directly |
EmbeddedDatabaseBuilder | n/a | creates an in-memory DB (review #5) |
Boot's auto-configuration picks the first pool it finds on the classpath, in this order:
HikariCP → Tomcat JDBC → Commons DBCP2 → Oracle UCP. Override with
spring.datasource.type. The reason it matters — and the reason the "not a pool" options are traps —
is that DriverManagerDataSource pays a full JDBC handshake per request and
SingleConnectionDataSource serialises every thread onto one connection.
86%, your second-best testing score. One miss, and it's about transaction scope rather than test wiring.
@Transactional on a test classtestB() would then run with no transaction and no
rollback — a real behavioural difference.What Spring's test support actually does with @Transactional:
| Behaviour | Detail |
|---|---|
| Scope | a new transaction per test method, not one for the class |
| Default outcome | rolled back after every method — this is the opposite of production |
| Commit instead | @Commit or @Rollback(false), at class or method level |
| Run code outside the transaction | @BeforeTransaction / @AfterTransaction |
| Class vs method | method-level annotations override the class-level default |
The rollback default is the fact to hold on to — it exists so tests don't leak
state into one another, and it's why @DataJpaTest is transactional by default too. Two consequences
worth knowing: a rolled-back test never exercises the real commit, so constraint violations that only surface at
flush time can hide (use @Commit or an explicit flush()); and code that starts its own
thread — or runs with REQUIRES_NEW — is outside the test transaction and will not be rolled
back.
75% — your best MVC result in seven attempts.
RestTemplate requestHttpEntity holding HttpHeadersRestTemplate is a shared,
thread-safe bean, so per-request state can't live on it.Per request you wrap headers in an HttpEntity and use exchange();
globally you add an interceptor:
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(token);
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Void> entity = new HttpEntity<>(headers);
ResponseEntity<User> res = restTemplate.exchange(
"/users/{id}", HttpMethod.GET, entity, User.class, 1);
| Scope | Mechanism |
|---|---|
| One request | HttpEntity<T> (headers, or headers + body) passed to exchange() / postForObject() |
| Every request | a ClientHttpRequestInterceptor added to the RestTemplate |
| Build-time defaults | RestTemplateBuilder.defaultHeader(…) in Boot |
The distractor worth pinning down: @RequestHeader is server-side — it reads an
incoming header in a controller method. Client-side sending and server-side reading are opposite directions, and
the exam pairs them deliberately. Note also that HttpEntity is the request-side type;
ResponseEntity extends it and adds the status code.
TransactionInterceptor is @Around-style@AfterThrowing with throwing=; a result parameter ⇒ @AfterReturning with returning=args = argument types; @within = declaring class; @target = target's runtime class; bean(…) = bean name/actuator; base-path changes it; only health is exposed over HTTPMETA-INF/spring.factories; Boot 2.7+ moved auto-config to META-INF/spring/…AutoConfiguration.importsbanner.txt in resources or the Banner interface; spring.main.banner-mode=off disables; no spring.banner.textRUNTIME retention@Resource and @Inject are alternativesNoUniqueBeanDefinitionExceptionT() statics · ![] projection · ?[] selection · ^[]/$[] first/last · ?. safe navigation · #{} is SpEL, ${} is a placeholderEmptyResultDataAccessException, >1 ⇒ IncorrectResultSizeDataAccessException; all uncheckedTransactionTemplate (on a PlatformTransactionManager); declarative = @Transactional@Commit/@Rollback(false) override; method beats classHttpEntity per request, ClientHttpRequestInterceptor for all; @RequestHeader is server-sideargs/@args, within/@within, target/@target), and the proxy model.
That single topic is bigger than your gap.
(2) Do the drills, don't just read. Q17 proves the point: you read review #6's answer this morning and
still missed the same question this afternoon. Every review page has interactive drills — clicking through them is
what converts reading into recall.
(3) Rotate all six sections, not the worst one. Data Management has swung 91 → 36 → 75 → 57 because it only
ever gets attention when it's the problem. Your seven checklists are 142 facts; a full pass takes about
45 minutes.
(4) The clock — this is now the last unfixed habit. 45 → 49 → 40 minutes across three papers, out of 130.
Eight of today's eighteen misses were multiple ticks on single-answer questions, and Q24 had you choosing two
invented URLs over the real one. You are not short of knowledge. You are short of forty minutes of care.
/bootactuator, /endpoint/actuator,
banner.properties, META-INF/boot, META-INF/config,
TransactionExecutor, DatabaseConnectionFactory. Seven fakes on one paper —
the exam relies on you not checking.And the target for the next sitting: still be in the chair at the 90-minute mark. You have used 40, 49 and 45 minutes on your last three papers out of 130 available. There is no version of this exam where finishing in a third of the time helps you.