Exam Review #11 · 29 Aug 2026 · 18 to fix

Eleventh attempt — Spring MVC hit 100%, and Spring Core is now the whole problem

42/60 again. But the section that had been your weakest for a month — Spring MVC — went from 50% to 100% with zero misses, the largest single-section gain of the entire series. You drilled three MVC rounds and the section is now finished. Spring Core fell to 58% and now carries 7 of the 18 misses, with AOP and SpEL the two clusters inside it. Plus two more polarity slips — the sixth and seventh times a "which is NOT" stem has been answered in the positive.

100%
Spring MVC (was 50%)
58%
Spring Core — 7 misses
86%
Data — best of the series
+4
Questions to pass
Official result · practice exam

70% — you did not pass this time

76% required to pass · 60/60 answered · 42 correct · time used 35m 14s of 2h 10m
Spring MVC 100%▲ 500 misses Data Management 86%▲ 42 misses Spring Boot 75%▼ 114 misses Testing 60%▲ 274 misses Spring Core 58%▼ 157 misses Spring Security 50%▲ 171 miss

Four of six sections went up, and the top one went all the way. Spring MVC had never been above 75% in ten attempts and sat at 50% two days ago. After three drill rounds it scored 100% with no misses — a +50 point move, the largest in the series. Data Management reached 86%, also its best.
Spring Core is now unambiguously the target. 58% is its worst since attempt #6, and it holds 7 of the 18 misses. Inside it, two clusters: AOP (3) and SpEL (2).
The clock slipped back. 35m 14s, down from 42m39s on each of the last two papers. That's 95 minutes unused, and the two polarity errors below are exactly what the extra time prevents.

Spring MVC is finished — and that is the method working, not luck

SectionBefore its clinicAfterSince
Data Management57%75%81 → 82 → 86%
Spring Boot56%86%75%
Spring MVC (3 rounds)50%100%

Three clinics, three immediate jumps, and the gains hold. Data has stayed in the 75–86% band across four papers since its clinic. MVC took three rounds and 80 drills — more than any other topic — and produced the biggest gain. The pattern is now established well enough to predict: build the clinic, drill it, the section moves 18–50 points.

Spring Core has never had one. It is the last section without a clinic, and it is now your worst.

How to get the last four marks

BucketMarksWhat it costs
AOP
Q4 advice annotations · Q14 @Around · Q19 AspectJ syntax
3 One topic, one evening. Lesson 7.
Polarity slips
Q7 "which is NOT auto-configured" · Q46 "which is INCORRECT"
2 Zero study. Say what you're hunting for before reading the options.
SpEL
Q16 where it can be used · Q37 standalone API
2 Lesson 5, one section.
Already taught here
Q10 fat jar (third time) · Q25 info endpoint · Q29 logging · Q12 random port
4 Re-drill the Boot clinic. ~20 minutes.

Buckets ① and ② alone are 5 marks against a gap of 4 — one topic plus one habit. Add ③ and ④ and you are at 11, comfortably clear.

Section scores, attempts #7 to #11

Section#7#8#9#10#11 · 29 AugVerdict
Spring MVC75%40%57%50%100%Finished — 3 clinics
Data Management57%75%81%82%86%Best of the series
Spring Boot64%71%56%86%75%Holding post-clinic
Testing86%100%100%33%60%Recovering
Spring Security100%100%75%33%50%Only 1 miss — small section
Spring Core65%61%75%73%58%Worst since #6 · no clinic yet
Overall70%70%73%70%70%Flat total, moving parts
Eleven attempts, and the shape of the problem has changed completely. In attempt #6 you were below 60% in three sections at once. Today two sections are at 86% and 100%, and the damage is concentrated in one section with no clinic. The overall total has been flat at 70–73% for five papers, but that is because each clinic's gain has been offset by whatever hadn't been covered yet — and there is now only one thing left uncovered.

Spring Core is the biggest section on the exam (roughly a quarter of the questions), it has never been above 75%, and it holds 7 of today's 18. Your eleven reviews now hold 212 corrected facts.
Your failure modes — 18 misses

Two of these questions have errors in their own explanations — read this before you revise them

Q2 contradicts itself. The option-level note says "@Transactional on an interface works only with interface-based (JDK dynamic) proxies — NOT class-based (CGLIB)". The summary at the bottom says the exact opposite: "On interfaces: works only with CGLIB (class-based) proxies, not JDK dynamic proxies." The option-level note is the correct one. With a CGLIB proxy Spring generates a subclass of your class, and Java does not inherit annotations from interfaces onto a subclass — so an interface-level @Transactional is invisible. The Spring reference documentation's advice is to annotate concrete classes, not interfaces, precisely because Boot defaults to CGLIB.

Q25 states outdated behaviour. It says the info endpoint is "exposed via both HTTP and JMX by default". That was true in Boot 2.0–2.4. Boot 2.5 removed info from the default HTTP exposure — since then only health is exposed over HTTP. Your exam targets Boot 2.5, so if a question names a version, go with health only; if it doesn't, this bank clearly expects the older answer. The Boot clinic flags the same conflict.

Neither changes what you should have ticked on the day — but both are worth knowing so you don't memorise something wrong from the material.

The 18 questions you failed

Your answer is reconstructed from the exported result — if a line looks wrong, tell me and I'll fix it.

QTopicWhat you answeredThe answer
Q2@Transactional facts"On an interface, works only with class-based proxies"Public methods only · default propagation REQUIRED
Q4Advice annotations"@Component"@Before · @AfterReturning
Q7What @WebMvcTest does not configure"Jackson" + "Caching" — both ARE configuredTransaction management
Q8REQUIRES_NEW when the inner failsThree wrong options tickedBoth roll back — the exception still propagates
Q10Fat jar vs regular jar"The fat jar is smaller" — third timeExecutable · manifest · all dependencies
Q11@MockBean"Same as @Mock, different library"Adds a mock to the ApplicationContext
Q12Testing on a random port"No webEnvironment" + "server.port=8080"RANDOM_PORT · server.port=0
Q14What the @Around aspect does"Batches DB operations" + "makes methods idempotent"Starts and commits a transaction around the call
Q16SpEL statements"Can only be used inside annotations"Also XML, and it supports literals
Q17Authentication mechanismsUnder-selected — five of six were correctX.509 · Digest · Basic · OAuth2/OIDC · Form (not LDAP)
Q19Which expression syntax Spring AOP uses"AssertJ" + "JS" — neither existsAspectJ pointcut expressions
Q25The info endpoint"Custom data can't be supplied"Via info.* properties or InfoContributor
Q29Default logging implementation"Java Util Logging" + "Log4J2"Logback
Q30Registering a BeanPostProcessorNon-static @Bean + @Bean without @ConfigurationA static @Bean method
Q35Starter dependency management"Each starter must declare its own version"Versions come from the Boot BOM
Q37SpEL standalone"SpelParser/SpelContext" (invented) + "No, only via @Value"ExpressionParser + EvaluationContext
Q46Which @WebMvcTest statement is incorrectTwo correct statements tickedYou don't need @ExtendWith — it's built in
Q54What Java 8 interfaces can declare"Regular method implementation" + "friend methods"static · constants · nested types · default

Jump to a section

① Spring Core — AOP — 3 ② Spring Core — SpEL — 2 ③ Spring Core — the rest — 2 ④ Testing — 4 ⑤ Spring Boot — 4 ⑥ Data & transactions — 2 ⑦ Security — 1

① Spring Core — AOP 3 misses

The largest single cluster on the paper, and the cheapest to close. AOP is one self-contained topic: five advice types, a handful of designators, one proxy model.

Q4 · Which annotations declare an advice method

@Before and @AfterReturning@Aspect and @Component mark the class

Your answer: you ticked @Component. The question separates class-level annotations from method-level ones, and both wrong options are class-level.
LevelAnnotationsPurpose
Class@Aspect"this class contains advice and pointcuts"
Class@Component"make it a Spring bean" — required, or Spring never sees the aspect
Method@Before · @After · @AfterReturning · @AfterThrowing · @Aroundthe five advice types
Method@Pointcuta named, reusable pointcut expression

Both class-level annotations are needed together, and that's a stock exam point: @Aspect alone does nothing, because Spring only weaves aspects that are beans. You need @Component (or a @Bean method) as well.

And the version fact that pairs with it: all these annotations come from AspectJ (org.aspectj.lang.annotation), not from Spring. Spring interprets them with its own proxy runtime — which is exactly what Q19 below is about.

Memory hook: @Aspect + @Component mark the CLASS. The five advice annotations mark METHODS. @Aspect without @Component is invisible.
Q14 · What an @Around transaction aspect achieves

It starts and commits a transaction around every matched call

Your answer: "it batches database operations" and "it makes methods idempotent". AOP does exactly what the advice body says and nothing more — it adds no behaviour of its own.

Read the advice body and the answer is written there:

@Around("execution(* com.example.service.*.*(..))")
public Object manageTransaction(ProceedingJoinPoint jp) throws Throwable {
    System.out.println("Transaction started.");     // ← before
    Object result = jp.proceed();                    // ← the real method
    System.out.println("Transaction committed.");    // ← after
    return result;
}

The general principle the distractors miss: AOP is a mechanism for inserting code, not a source of behaviour. It cannot batch, synchronise or make anything idempotent unless you write that code in the advice. If an option claims AOP does something "automatically", ask where that code would live.

And the connection worth making: this is a simplified version of what Spring's own @Transactional does. TransactionInterceptor is an @Around-style MethodInterceptor that begins a transaction, calls proceed(), and then commits or rolls back. Understanding this one aspect explains @Transactional's proxy limitations too.

One flaw in the code worth spotting: there is no try/catch, so if the method throws, "Transaction committed" never prints and nothing rolls back. A real @Around transaction aspect needs a catch.

Memory hook: @Around = before + proceed() + after. AOP inserts YOUR code; it invents no behaviour. @Transactional is exactly this pattern.
Q19 · Which expression syntax Spring AOP uses two invented options

AspectJ pointcut expressions — not SpEL

Your answer: "AssertJ expression syntax" and "JS expression syntax". AssertJ is a test-assertion library; JavaScript has no role in Java AOP. Neither is an expression syntax Spring uses anywhere.

The genuinely interesting distractor was SpEL, and the distinction is worth owning because both are "Spring expression languages":

LanguageUsed forLooks like
AspectJAOP pointcuts onlyexecution(* com.example.service.*.*(..))
SpEL@Value, @Cacheable(key=…), @PreAuthorize, @ConditionalOnExpression#{2 * T(Math).PI}

Why Spring borrowed AspectJ's syntax rather than inventing one: AspectJ already had a mature, well-specified pointcut language, and Spring wanted aspects to be portable between proxy-based Spring AOP and full AspectJ weaving. So aspectjweaver is a required runtime dependency — Spring uses it to parse and match expressions, even though it never does byte-code weaving.

The designators Spring AOP supports: execution, within, args, this, target, @annotation, @within, @target, @args, plus Spring's own bean(…). Spring AOP supports only method-execution join points — AspectJ's call, get, set and initialization throw IllegalArgumentException.

Memory hook: Pointcuts = AspectJ syntax (and aspectjweaver is required). SpEL is for @Value, caching, security — never pointcuts.

② Spring Core — SpEL 2 misses

Q16 · Where SpEL can be used

Annotations and XML and programmatically — and it supports full arithmetic

Your answer: "it can only be used inside annotations". An absolute — and the question's other false option ("logical and relational but not mathematical") is the same shape.
WhereExample
Annotations@Value("#{2 * 60}")
XML configuration<property name="timeout" value="#{30 * 1000}"/>
Programmaticallynew SpelExpressionParser().parseExpression(…)
Spring Security@PreAuthorize("hasRole('ADMIN')")
Caching@Cacheable(key = "#id")
Spring Data@Query("… :#{#user.id}")

And the operators, since the other distractor claimed maths was missing: arithmetic + - * / % · relational == != < > <= >= · logical and or not (or && || !) · ternary ?: · Elvis ?: · safe navigation ?. · type reference T() · projection ![] · selection ?[].

Literals are supported too: strings 'hello', numbers, true, false, null. That was the second correct option.

Memory hook: SpEL runs anywhere Spring evaluates a #{} — annotations, XML, security, caching, and standalone. Full arithmetic included.
Q37 · Using SpEL outside an ApplicationContext invented class names

ExpressionParser + EvaluationContextspring-expression is a standalone library

Your answer: "SpelParser and SpelContext" (both invented) and "No — SpEL only works via @Value in a Spring container". The second is the more interesting error: it assumes SpEL is a container feature. It isn't — it's a library.
ExpressionParser parser = new SpelExpressionParser();

String s = parser.parseExpression("'Hello ' + 'World'").getValue(String.class);

User u = new User("Alice", 30);
EvaluationContext ctx = new StandardEvaluationContext(u);
boolean adult = parser.parseExpression("age >= 18").getValue(ctx, Boolean.class);

The naming rule that would have caught the fake: the interfaces are generic — ExpressionParser, EvaluationContext — and the implementations carry the prefix: SpelExpressionParser, StandardEvaluationContext. SpelParser and SpelContext are truncations — real Spring names are longer and more explicit, not shorter.

Two facts worth carrying: spring-expression depends only on spring-core, so it runs in any plain-Java program; and for untrusted input use SimpleEvaluationContext rather than StandardEvaluationContext, which exposes reflection, method invocation and constructor calls.

Memory hook: SpelExpressionParser + StandardEvaluationContext. Interfaces are generic, implementations carry a prefix. Truncated names are fakes.

③ Spring Core — the rest 2 misses

Q30 · Registering a BeanPostProcessor

A static @Bean method in a @Configuration class

Your answer: a non-static @Bean method and a @Bean without @Configuration. Both work "in practice" and both carry the same ordering risk — which is exactly what the question is about.

The problem is a chicken-and-egg ordering conflict. A BeanPostProcessor must exist before other beans are created, because it processes them. But a non-static @Bean method requires its enclosing @Configuration class to be instantiated first — and that class is itself a bean that wants post-processing.

@Configuration
public class InfrastructureConfig {

    @Bean
    public static LoggingBeanPostProcessor loggingBPP() {   // ← static
        return new LoggingBeanPostProcessor();
    }
}

static breaks the cycle — Spring can invoke a static method without instantiating the class, so the BPP is available very early. Declare it non-statically and Spring logs:

BeanPostProcessor [X] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

The same rule applies to BeanFactoryPostProcessors — which is why PropertySourcesPlaceholderConfigurer and CustomScopeConfigurer are conventionally declared static too. Anything that processes other beans should be a static @Bean method.

One consequence to remember: static @Bean methods are not CGLIB-intercepted, so calling one from another method creates a new instance rather than returning the singleton. Use static only for post-processors, never for ordinary beans other beans depend on.

Memory hook: Anything that post-processes beans (BPP, BFPP, placeholder/scope configurers) = a static @Bean method. Static breaks the ordering cycle.
Q54 · What a Java 8 interface can declare

static methods · constants · nested types · default methods

Your answer: "regular method implementation" and "friend methods". friend is C++ — Java has no such keyword. And a body in an interface requires default or static.
MemberAllowed?Since
Abstract methodsyes1.0
Constants (implicitly public static final)yes1.0
Nested types (implicitly public static)yes1.0
default methodsyesJava 8
static methodsyesJava 8
private methodsyesJava 9
A regular (non-default, non-static) bodyno
"friend" methodsno such concept in Java

Why default was added is the Spring-relevant part: it lets an interface gain new methods without breaking every existing implementation. The JDK used it to add Collection.stream() and Comparator.reversed() — and Spring used the same trick in 5.0, making both BeanPostProcessor methods default so implementations only override the one they care about. That connects directly to Q30 above.

Two rules worth having: a default method cannot redeclare an Object method (equals, hashCode, toString) — compile error; and static interface methods are not inherited — you must qualify them with the interface name.

Memory hook: Java 8 interfaces: abstract + constants + nested types + default + static. Java 9 adds private. No "friend" — that's C++.

④ Testing 4 misses

33% → 60%, recovering. Two of the four are polarity slips, not knowledge.

Q7 · What @WebMvcTest does NOT auto-configure polarity

Transaction management — Jackson, templating and caching all are configured

Your answer: Jackson and Cachingtwo things @WebMvcTest definitely does configure. The stem asked for the exception.
Loaded by @WebMvcTestNOT loaded
@Controller, @ControllerAdvice, @JsonComponent@Service, @Repository, @Component
WebMvcConfigurer, Filter, HandlerInterceptorDataSource, JPA, transaction management
Converter, HandlerMethodArgumentResolverfull @EnableAutoConfiguration
Jackson (an ObjectMapper) · templating · caching · MockMvc

The rule behind the slice: @WebMvcTest loads what the web layer needs — anything a controller might touch while producing a response. Jackson serialises the body, templates render views, caching annotations may sit on web components. What it excludes is the persistence layer, which is why you mock the service with @MockBean.

On the polarity slip. This is the sixth across your papers. The fix is one sentence said before you look at the options: "I am hunting for the one thing that is NOT there." With that in mind, Jackson and caching cannot survive — you know they're loaded.

Memory hook: @WebMvcTest = the web layer and everything it needs to respond. It excludes persistence — services, repositories, DataSource, transactions.
Q46 · Which @WebMvcTest statement is INCORRECT polarity

You do not need @ExtendWith(SpringExtension.class) — it's built in

Your answer: "it allows specifying a single controller" and "it is a class-level annotation"both of which are true. The seventh polarity slip, on the same paper as the sixth.

Since Boot 2.1, every test-slice annotation is meta-annotated with @ExtendWith(SpringExtension.class):

@WebMvcTest(UserController.class)          // ← this is the whole thing
class UserControllerTest {
    @Autowired MockMvc mockMvc;
    @MockBean UserService userService;
}

Adding @ExtendWith yourself is harmless but redundant. The same is true of @SpringBootTest, @DataJpaTest, @JsonTest and the rest — one annotation is always enough.

Two polarity slips on one paper is the signal to change something mechanical. Both stems contained a capitalised or emphasised negative — NOT, INCORRECT — and both were answered in the positive. Before reading any option, state the target out loud. You have 95 spare minutes; this costs five seconds a question.

Memory hook: All Boot test slices already include SpringExtension. One annotation is enough. And a capitalised NOT/INCORRECT means stop and restate the target.
Q11 · What @MockBean is for

It puts a Mockito mock into the ApplicationContext@Mock does not

Your answer: you ticked "@MockBean serves the same purpose as @Mock, just from a different library". That's the one false statement — and the distinction is the whole reason @MockBean exists.
@Mock (Mockito)@MockBean (spring-boot-test)
Creates a mockyesyes
Knows about the Spring contextnoyes
Replaces an existing beannoyes
Injected into other beansnoyes
Creates a bean if none existsn/ayes

The practical difference: @Mock gives you an object you must wire in by hand — fine for a plain unit test. @MockBean registers a bean definition, so the controller Spring instantiates receives the mock. That's what makes it usable inside @WebMvcTest.

The performance pitfall worth knowing: each distinct combination of @MockBean types produces a different context cache key, so a new ApplicationContext is built. Scattering many different mock combinations across test classes destroys context caching and slows the suite badly.

Version note: in Spring Framework 6.2 / Boot 3.4 this moved to @MockitoBean in spring-test, with @MockBean deprecated. Your exam targets Boot 2.5, where @MockBean is correct.

Memory hook: @Mock = an object. @MockBean = a bean definition in the context, replacing or creating one. Different combinations = different contexts.
Q12 · Running an integration test on a random port

@SpringBootTest(webEnvironment = RANDOM_PORT) — or server.port=0

Your answer: "@SpringBootTest without webEnvironment" and "server.port=8080". The first gives you no server at all; the second is the opposite of random.

Two genuinely equivalent routes, and both were correct:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyIT {
    @LocalServerPort int port;
    @Autowired TestRestTemplate restTemplate;
}

# or — src/test/resources/application.properties
server.port=0        # 0 means "any free port" at the servlet-container level

server.port=0 is the underlying mechanism, and that's why the two are equivalent: RANDOM_PORT sets exactly that property for you. Port 0 is a long-standing TCP convention meaning "let the OS pick a free one".

And the default that made the first option wrong: @SpringBootTest defaults to MOCK — a mock servlet environment with no server and no port, which is why TestRestTemplate isn't auto-configured there. That fact has now appeared on three of your papers.

Memory hook: RANDOM_PORT or server.port=0 — the first sets the second. Default is MOCK: no server, no port, no TestRestTemplate.

⑤ Spring Boot 4 misses

86% → 75%, still well above where it was before its clinic. All four of these are in the Boot clinic.

Q10 · Fat jar vs regular jar third time — #3, Boot clinic, here

The fat jar is larger, executable, and carries the dependencies

Your answer: you ticked "the fat jar has a smaller size than the original jar". It contains everything the original does plus every dependency plus the loader.
Original jarFat jar
Sizesmallstrictly larger
Main-Classyours or absentorg.springframework.boot.loader.JarLauncher
Start-Classabsentyour @SpringBootApplication class
DependenciesnoneBOOT-INF/lib/*.jar, nested
java -jarnoyes

Missed three times, so here's a way to make it stick that isn't a table: "fat" is the name. A fat jar is called fat because it is bigger — it has eaten all its dependencies. If an option says a fat jar is smaller, the option contradicts the name in the question.

The mechanism, once: the JDK class loader cannot read a jar nested inside another jar. So Boot ships JarLauncher and LaunchedURLClassLoader inside the archive, points Main-Class at the launcher, and records your real main class as Start-Class.

Memory hook: "Fat" means bigger — it ate its dependencies. Main-Class = JarLauncher, Start-Class = yours, deps nested in BOOT-INF/lib.
Q29 · The default logging implementation pairs with #9's Q2

Logback — and this is the other half of a question you also missed on attempt #9

Your answer: Java Util Logging and Log4J2. Both are supported alternatives, neither is the default.

You have now missed both halves of the same two-layer fact, which is why it's worth pinning down properly:

QuestionAsks aboutAnswer
Attempt #9 Q2the API Spring's own code logs throughCommons Logging (JCL)
This paper Q29the implementation that writes outputLogback
Spring's own code
   → Commons Logging          (the API it compiles against)   ← attempt #9's answer
       → Logback              (the default implementation)     ← this paper's answer
       or Log4J2, or JUL      (if you swap the starter)

Read which layer the stem means. "Used for internal logging" / "logging API" ⇒ Commons Logging. "Default logging implementation" / "what writes the output" ⇒ Logback. Facade versus implementation is the whole distinction, and the same shape as SLF4J-vs-Logback.

Switching: exclude spring-boot-starter-logging and add spring-boot-starter-log4j2. Without the exclusion both bindings are on the classpath and Logback silently wins.

Memory hook: Spring logs THROUGH Commons Logging. Logback WRITES the output. API vs implementation — two questions, two answers.
Q25 · The info endpoint Boot clinic §1

Custom data can be supplied — via info.* properties or InfoContributor

Your answer: you ticked "custom data can't be supplied to this endpoint". An absolute, and supplying custom data is essentially the endpoint's entire purpose.
SourceHow
Static propertiesinfo.app.name=…, info.app.version=…
Build informationthe Boot Maven/Gradle plugin generates build-info.properties
Source controlgit.properties from the git-commit-id plugin
Anything dynamica @Component implementing InfoContributor

Remember it as the read-only twin of loggers: info exposes arbitrary data you supply and changes nothing; loggers is the one that accepts a POST and mutates state at runtime.

See the errata note above about this question's claim that info is HTTP-exposed by default — true for Boot 2.0–2.4, not for 2.5+.

Memory hook: info = arbitrary, read-only app data from info.*, build-info, git.properties or an InfoContributor.
Q35 · Starter-based dependency management

Starter versions come from the Boot BOM — you never declare them

Your answer: you ticked "each starter must declare its own version explicitly because Spring Boot does not manage starter versions". That is the precise opposite of what starters are for.
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'   // ← no version
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

The io.spring.dependency-management plugin (Gradle) or the spring-boot-starter-parent POM (Maven) imports Boot's BOM, which pins a compatible version for every managed dependency. That version curation is the main thing a starter buys you — not just the grouping.

StarterBundlesDoes not include
starter-webSpring MVC, Jackson, embedded Tomcat
starter-data-jpaSpring Data JPA, Hibernate, spring-orm, HikariCPa database driver
starter-testJUnit 5, Mockito, AssertJ, Hamcrest, Spring Test, JSONassertEasyMock

The other correct-rejection here: starter-data-jpa does not add an in-memory database — you add H2 or Postgres yourself. Same principle as "Boot ships no vendor JDBC drivers" from attempt #8.

Memory hook: Starters group dependencies AND pin versions via the BOM. They never include a database driver.

⑥ Data & transactions 2 misses

86% — the best Data score of the series, four papers after its clinic.

Q2 · @Transactional facts see the errata note

Public methods only · default propagation REQUIRED

Your answer: you ticked "on an interface, it works only with class-based (CGLIB) proxies". Backwards — it works only with interface-based (JDK) proxies.

Why interface annotations vanish under CGLIB: a CGLIB proxy is a subclass of your class. Java does not inherit annotations from an interface onto an implementing class, and certainly not onto a generated subclass — so Spring's attribute source never sees the interface-level @Transactional. A JDK dynamic proxy implements the interface, so the annotation is visible.

Annotation placed onJDK proxyCGLIB proxy
a concrete class or its methodworksworks
an interface or its methodworksignored

Spring Boot defaults to CGLIB (proxyTargetClass=true), which is why the Spring reference documentation says: annotate concrete classes, not interfaces. This is also the safer habit generally — it removes the proxy type from the equation entirely.

The two correct options are worth over-learning, since they're the stock @Transactional facts: public methods only (non-public is silently ignored — no error), and default propagation REQUIRED, default isolation DEFAULT, rollback on unchecked exceptions only.

Memory hook: @Transactional on an interface works with JDK proxies only — and Boot uses CGLIB. So annotate concrete classes. Public methods only, propagation REQUIRED.
Q8 · REQUIRES_NEW when the inner transaction fails

Both roll back — independence governs rollback, not exception flow

Your answer: three wrong options ticked, and the correct one wasn't among them. The near-miss you took — "subOperation rolls back, mainOperation continues unaffected" — would be right only if the outer method caught the exception.

Trace it precisely, because this is the subtlest transaction question you've had:

StepWhat happens
1mainOperation() starts TX-A
2subOperation() is REQUIRES_NEW → TX-A is suspended, TX-B starts
3subOperation() throws → TX-B rolls back independently ✔
4the exception propagates into mainOperation(), which has no try/catch
5it crosses TX-A's boundary → TX-A is marked rollback-only and rolls back too

The one-line version: REQUIRES_NEW isolates the transactions, not the exceptions. Independence means TX-B's rollback doesn't drag TX-A down by itself — but nothing stops the exception travelling up the call stack in the ordinary Java way, and Spring rolls back on unchecked exceptions by default.

@Transactional
public void mainOperation() {
    try {
        subService.subOperation();        // TX-B rolls back
    } catch (Exception e) {
        log.warn("sub failed, continuing", e);   // ← now TX-A really does survive
    }
}

That try/catch is the difference between the option you picked and the correct one. It's also the real-world pattern: REQUIRES_NEW plus a catch is how you write an audit record that persists even when the main work fails.

Memory hook: REQUIRES_NEW isolates transactions, not exceptions. Without a try/catch in the caller, both roll back.

⑦ Spring Security 1 miss

Q17 · Which are authentication mechanisms

Five of six — LDAP is a directory protocol, not a mechanism

Your answer: under-selected. X.509, Digest, Basic, OAuth 2.0/OIDC and Form are all mechanisms; only LDAP isn't.

The distinction the question is built on is genuinely useful:

LayerQuestion it answersExamples
MechanismHow are credentials collected and transmitted?Basic, Digest, Form, X.509, OAuth2/OIDC
User storeWhere are the users kept?LDAP, JDBC, in-memory

The two layers combine: a Form login collects a username and password, and an LdapAuthenticationProvider verifies them against an LDAP directory. Same request, two different concerns.

This connects to a fact you already have from attempt #9: the question "where can Spring Security store user details?" has the answer JDBC, LDAP, in-memory — and LDAP is on that list precisely because it's a store, not a mechanism. The same word is the right answer to one question and the wrong answer to the other. Read which layer the stem is asking about.

Memory hook: Mechanism = how credentials arrive (Basic, Digest, Form, X.509, OAuth2). Store = where users live (LDAP, JDBC, in-memory). LDAP is a store.

Your close-the-gap checklist — attempt #11

The 18 facts, one line each
How to improve — in order of value per minute (1) Say what you're hunting for, before reading any option. Two polarity slips on this paper (Q7, Q46), seven across the series. Both stems had a capitalised negative — NOT, INCORRECT — and both were answered in the positive. Five seconds a question, worth 2 marks here and half the gap. (2) Spend one evening on AOP. Lesson 7 — five advice types, the designators, the proxy model. 3 marks, one topic, and it also explains @Transactional's behaviour (Q2 and Q8 above). (3) Then SpEL. Lesson 5 — 2 more marks, and it overlaps with caching and security expressions. (4) Re-drill the Boot clinic. All four Boot misses are in it, and the fat jar has now cost you three marks across three papers. (5) Slow back down. 35 minutes, from 42 on each of the last two papers. You have 95 minutes spare and 10 of 18 misses were multiple ticks on one-answer questions. Target 60 minutes.

Where you are after eleven attempts

Finished: Spring MVC (100%, zero misses, after three drill rounds). Strong: Data 86% — best of the series — and Boot 75%, both holding above their pre-clinic levels. Recovering: Testing 60%, Security 50% off a single miss. The work: Spring Core at 58%, holding 7 of 18 misses. It is the biggest section on the exam, it has never been above 75%, and it is the only section without a clinic.

Three clinics have each moved their section 18–50 points and the gains have held. There is one section left, and it happens to be the one carrying most of your remaining losses. Ask for the Spring Core clinic and you have covered the whole syllabus.

I'm your teacher — ask me anything. The obvious next step is "build me a Spring Core clinic" — it's the last section without one, it's the biggest on the exam, and it holds 7 of these 18. Point me at a Core topic bank and I'll build it the same way. Or say "drill AOP" for the 3-mark cluster, "drill the polarity questions" for a round made entirely of which is NOT stems, or "quiz me on the 18" for this attempt.
← Dashboard ← Review #10 Lesson 7 · AOP Boot clinic