Exam Review #9 · 26 Aug 2026 · 16 to fix

Ninth attempt — 73%, your best score yet, and two marks from the pass

44/60. That beats attempt #4's 72%, which had stood as your ceiling for eight days. You need +2 — the smallest gap of the series. And the reason is not a mystery: you slowed down. 28m46s yesterday evening → 42m30s today, and the misses fell from 18 to 16 while three sections rose. Spring Core broke 71% for the first time in nine attempts. Two things are left, and both are things you already have: Actuator, which has now cost you marks in four consecutive papers, and nine of these sixteen are facts an earlier review already taught you.

73%
This attempt (44/60)
72%
Previous best (#4)
76%
Pass mark (46/60)
+2
Questions to pass
Official result · practice exam

73% — you did not pass this time

76% required to pass · 60/60 answered · 44 correct · time used 42m 30s of 2h 10m
Testing 100%— held0 misses Data Management 81%▲ 64 misses Spring Core 75%▲ 143 misses Spring Security 75%▼ 251 miss Spring MVC 57%▲ 173 misses Spring Boot 56%▼ 155 misses

Three sections up, and one of them broke a nine-attempt ceiling. Spring Core had never once been above 71% across eight papers — today it hit 75%. Spring MVC recovered from yesterday's 40% to 57% without a clinic, just from review #8's return-types table. Data reached 81%, its best since attempt #4. Testing held 100% for a second consecutive paper.
Spring Boot is now the problem, and it is specifically Actuator. 56%, five misses, and Q13 and Q15 are the same distinction asked twiceenabled versus exposed. That pairing has now appeared in reviews #6, #7, #8 and this one. It is the single most repeated topic in the entire series.

The clock finally moved the right way — and the score moved with it

45m
#5 · 70%
49m
#6 · 58%
40m
#7 · 70%
29m
#8 · 70%
42m
#9 · 73%

Every review since #5 has said the same thing about the clock, and this is the first paper where it changed. You spent 13 minutes 44 seconds longer than yesterday evening and got your best result in nine attempts: misses down from 18 to 16, three sections up, a nine-attempt ceiling broken.

That is not proof on its own — one paper, and the question mix differs each time. But it points the same way as everything else in the data: 10 of today's 16 misses were still multiple ticks on a one-answer question, which is the error that extra time directly prevents. You are still using only 33% of the clock. There are 87 minutes sitting unused, and the two marks you need are almost certainly in them.

How to get the last two marks — the ledger

You asked to be clear on how to improve from here. With a gap of two, the question isn't "what should I study" — it's "which two marks are cheapest". Here is where the sixteen sit:

BucketMarksWhat it costs to fix
Facts an earlier review already taught you
Q5, Q13, Q14, Q15, Q18, Q28, Q36, Q45, Q57
9 Re-cover the six checklists + the Data clinic. ~45 minutes, no new material.
Actuator specifically
Q13 and Q15 — both the enabled vs exposed distinction
2 One table, below. Ten minutes, and it is exactly the gap.
Names that don't exist
filtersNone(), @EnableAnnotationTransaction, @AnnotationDrivenTransaction
2 One question per option. Zero minutes. Down from 4 marks last paper.
④ Genuinely new material (REST principles, Commons Logging, @Conditional, "lightweight", return types) 5 Real study — worth doing, not needed to pass.

Bucket ② alone is the pass. Two questions on this paper — Q13 and Q15 — turned on one sentence: every Actuator endpoint except shutdown is enabled, but only health is exposed over HTTP. Learn that sentence and, on this paper, you score 46.

Section scores, attempts #5 to #9

Section#5 · 19 Aug#6 · 25 am#7 · 25 pm#8 · 25 eve#9 · 26 AugVerdict
Testing88%70%86%100%100%Done — held twice
Data Management36%75%57%75%81%Best since #4 — the clinic holds
Spring Core71%57%65%61%75%Broke its nine-attempt ceiling
Spring Security60%33%100%100%75%Slipped, but off a high base
Spring MVC67%67%75%40%57%Recovering — still the weakest topic
Spring Boot92%40%64%71%56%Now the worst — and it's Actuator
Overall70%58%70%70%73%Best of nine
What nine attempts now show. The overall line went 70 → 58 → 70 → 70 → 73, and the floor under it has risen: your worst section today is 56%, where in attempt #6 it was 33%. Two sections are finished (Testing 100% twice running), two are strong (Data 81%, Core 75%), and the remaining damage sits in Boot and MVC.

And the pattern that hasn't shifted: 9 of 16 misses today were facts already written down in an earlier review. That number was 12 in #6, 7 in #7, and 9 here. It is consistently your largest bucket, and it is the one that costs nothing to close. Your nine reviews now hold 176 corrected facts.
Your four failure modes — 16 misses

The one table that is worth your two marks

Enabled and exposed are two independent switches. Q13 and Q15 both turned on this, and so did questions in reviews #6, #7 and #8.

Enabled — does the endpoint exist?Exposed — can you reach it?
Propertymanagement.endpoint.<id>.enabled
globally: management.endpoints.enabled-by-default
management.endpoints.web.exposure.include
management.endpoints.jmx.exposure.include
Defaultall enabled except shutdownHTTP: health only
JMX: * (everything)
So info is…enablednot exposed over HTTP ❌ (Boot 2.5+)
And loggers is…enabledJMX yes, HTTP no until you add it

Three sentences to memorise: (1) Everything is enabled except shutdown. (2) Over HTTP only health is exposed; over JMX everything is. (3) The exposure key contains web or jmx; the enablement key does not.

The 16 questions you failed

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.

QTopicWhat you answeredThe answer
Q1What REST is"REST is Stateful" + "REST is Relative"REST is interoperable — and stateless, and a style not a protocol
Q2Boot's internal logging API"Log4J2" + "SLF4J"Commons Logging (Logback is the default implementation)
Q4What @Conditional is for"environment config" + "app run statements"Conditional bean registration
Q5"@Transactional supports SpEL""True" — taught in #2 and #5False — fixed types only
Q13The loggers endpoint"level can be changed only via HTTP"Lists all loggers · changeable via HTTP or JMX
Q14@RestController equals…Both @SpringBootApplication options@Controller + @ResponseBody
Q15The info endpoint"only authenticated users" + "can change a property"Build/SCM info · arbitrary app information
Q17Bypassing the filter chain"filtersNone()" (invented) + "anonymous()"web.ignoring().antMatchers(…)
Q18Resolving autowiring ambiguityUnder-selected — missed one of three@Primary · @Qualifier("cat") on the field · rename the field
Q22Why Spring is "lightweight""no runtime needed" + "can't use POJOs"No JEE server · small modular JARs · low overhead
Q28What spring.factories can registerUnder-selected — all four were correctListeners · EnvironmentPostProcessors · auto-config filters · auto-config classes
Q36PreparedStatementCreatorThe RowMapper and ResultSetExtractor descriptionsBuild a PreparedStatement from the given Connection
Q45Why NamedParameterJdbcTemplateThree wrong options tickedNamed parameters → readability
Q47Enabling annotation-driven transactionsTwo invented annotations@Configuration + @EnableTransactionManagement
Q56Valid controller methods"@RequestBody on the return type"@RequestBody is input only; @ResponseBody is output
Q57@PostConstruct / @PreDestroy behaviour"always invoked regardless of scope"Prototypes get no @PreDestroy · called once · before destroy()
Nine of these sixteen are already written down somewhere in this site Q5 @Transactional + SpEL — #2, #5 · Q13 & Q15 Actuator enabled/exposed — #6, #7, #8 · Q14 @RestController — #7, #8 · Q18 ambiguity resolution — #8 · Q28 spring.factories — #7 · Q36 JdbcTemplate callbacksData clinic §6 · Q45 NamedParameterJdbcTemplate — #6, Data clinic · Q57 JSR-250 lifecycle — #5, #6, #8. That is 9 marks in documents you already own, against a gap of 2.

Jump to a section

① Spring Boot & Actuator — 5 misses ② Data & transactions — 4 ③ Spring MVC & REST — 3 ④ Spring Core — 3 ⑤ Spring Security — 1

① Spring Boot & Actuator 5 misses

56% — now your weakest section, and two of the five are the single table printed above.

Q15 · The Actuator info endpoint enabled vs exposed · #6, #7, #8

Build/SCM information and arbitrary app information — it is enabled by default, just not exposed

Your answer: you ticked "only an authenticated user can display it" and "it can change a property value on a running application". The second is the more useful error: info is strictly read-only. The endpoint that changes something at runtime is loggers — which is Q13, on the same paper.

Three ways to put data into info, all worth recognising:

SourceHow
Static propertiesinfo.app.name=…, info.app.version=… in application.properties
Build informationthe Boot Maven/Gradle plugin generates build-info.properties
Source controlgit.properties from the git-commit-id plugin
Anything dynamica @Component implementing InfoContributor
@Component
public class CustomInfo implements InfoContributor {
    @Override public void contribute(Info.Builder builder) {
        builder.withDetail("region", "eu-west-2");
    }
}

The option that looks true and isn't: "it is not enabled by default". info is enabled — every endpoint except shutdown is. What changed in Boot 2.5 is that info stopped being exposed over HTTP by default; in Boot 2.0 both health and info were. Since 2.5, only health is. Enablement ≠ exposure, and this question exists solely to test that you don't conflate them.

Security isn't specific to info either — it applies to every endpoint and is configured with Spring Security, not by the endpoint itself.

Memory hook: info is enabled, read-only, and not HTTP-exposed since Boot 2.5. Populate it with info.* properties, build-info, git.properties, or an InfoContributor.
Q13 · The Actuator loggers endpoint Actuator · fourth paper running

It lists every logger with its level, and levels can be changed over HTTP or JMX

Your answer: you ticked "the level can be changed only via HTTP". An absolute — and the word only is what makes it false. JMX works too.

loggers is the endpoint that makes Actuator genuinely operational rather than informational — it is read and write:

# read every logger and its level
GET  /actuator/loggers

# read one
GET  /actuator/loggers/com.example

# change one at runtime — no restart
POST /actuator/loggers/com.example
Content-Type: application/json
{"configuredLevel": "DEBUG"}
FieldMeaning
configuredLevelwhat you explicitly set (may be null)
effectiveLevelwhat actually applies — inherited from the parent logger if not configured

Two details that get asked. Posting {"configuredLevel": null} resets the logger to inherit from its parent — it does not restore the startup level. And the exposure rule from the table above applies here: loggers is enabled, visible over JMX by default, but needs management.endpoints.web.exposure.include=loggers before HTTP will serve it.

Memory hook: loggers is the writable one: GET to list, POST to change, over HTTP or JMX. configuredLevel vs effectiveLevel.
Q28 · What spring.factories can register taught in review #7

All four were correct

Your answer: under-selected. There was no wrong option to avoid — the fourth "everything is true" question of the series.

Review #7 covered the file's location (META-INF/spring.factories); this question tests its range. It is a general extension registry, not an auto-configuration-only file:

KeyRegisters
EnableAutoConfigurationauto-configuration classes — how custom starters work
AutoConfigurationImportFilterfilters that cut candidates out early, before conditions are evaluated
ApplicationListenerevent listeners active during startup
EnvironmentPostProcessorcode that mutates the Environment before the context exists
ApplicationContextInitializercontext customisation before refresh
FailureAnalyzerturns startup exceptions into readable diagnostics

Why it's a file rather than beans: every one of those runs before the ApplicationContext exists, so there is no container to look them up in. SpringFactoriesLoader reads the file from every JAR on the classpath and merges the entries.

The version fact from review #7 still applies: Boot 2.7 moved auto-configuration registration only to META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports; every other key stayed in spring.factories.

Memory hook: spring.factories registers anything that must exist before the context does — auto-config, filters, listeners, environment processors, failure analyzers.
Q2 · Which logging framework Boot uses internally

Commons Logging for its own code — Logback is the default implementation

Your answer: Log4J2 and SLF4J. SLF4J is the near-miss: it's a facade, and the right kind of answer — just not the one Spring itself uses.

There are two layers, and the question is about the upper one:

LayerWhatWhy
API used by Spring's own codeCommons Logging (JCL)org.apache.commons.logging.Logkeeps the framework decoupled from any implementation
Implementation that writes the outputLogback by default (via spring-boot-starter-logging)swappable for Log4J2 or JUL
Spring's own code
   → Commons Logging          (the API it compiles against)
       → Logback              (default)
       or Log4J2              (swap the starter)
       or java.util.logging

The historical detail that makes it stick: Spring committed to Commons Logging long before SLF4J existed, and its public API still exposes it. Since Spring 5, spring-jcl is a reimplementation of the Commons Logging API that delegates straight to SLF4J or Log4J2 if present — so you get JCL's interface with modern routing, and no commons-logging JAR.

In your code you should still use SLF4J (LoggerFactory.getLogger(...)) — the question is specifically about Spring's internals.

Memory hook: Spring logs through Commons Logging; Logback is what prints. Facade ≠ implementation.
Q4 · What @Conditional is for

Conditional bean registration

Your answer: "loading configuration based on environments" and "conditional app run statements". The first is a use case, not the mechanism — and it's the narrower claim, which is what makes it wrong.

@Conditional(SomeCondition.class) asks a Condition implementation "should this bean definition be registered?" during context startup. It's evaluated once, at bean-definition time — there is no runtime "app run statement" concept anywhere in it.

public class OnLinuxCondition implements Condition {
    public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata md) {
        return ctx.getEnvironment().getProperty("os.name").contains("Linux");
    }
}

@Bean
@Conditional(OnLinuxCondition.class)
public MyService myService() { … }

The connection worth making: @Conditional is the engine behind all of Boot's auto-configuration. Every @ConditionalOn… annotation is just @Conditional with a pre-written condition:

AnnotationRegisters the bean when…
@ConditionalOnClassa class is on the classpath
@ConditionalOnMissingBeanno bean of that type exists — this is how Boot "backs off"
@ConditionalOnPropertya property has a given value
@ConditionalOnWebApplicationrunning in a web context
@ConditionalOnExpressiona SpEL expression is true

And note the neighbour: @Profile is itself a @Conditional@Conditional(ProfileCondition.class). So "environment-based loading" is one instance of @Conditional, not its definition.

Memory hook: @Conditional = "register this bean only if…". Every @ConditionalOnX and @Profile is built from it.

② Data & transactions 4 misses

81% — your best Data score since attempt #4. The clinic is holding. Three of these four are in it or in an earlier checklist.

Q5 · "@Transactional supports SpEL" taught in #2 and #5

False — every attribute takes a fixed constant, enum or class literal

Your answer: True. Review #5's checklist says it in one line: "@Transactional doesn't support SpEL, so these are all fixed types."

Look at the attribute list and it's obvious there's nowhere for an expression to go:

AttributeType
propagation / isolationenum constants
timeoutint
readOnlyboolean
rollbackFor / noRollbackForClass<? extends Throwable>[]
transactionManagera plain String bean name

The comparison the exam actually wants — which annotations do take SpEL:

SpEL supportedNo SpEL
@Value("#{…}")@Transactional
@PreAuthorize / @PostAuthorize@Secured (role names only)
@Cacheable(key, condition, unless)@Scheduled (placeholders only)
@ConditionalOnExpression@Profile (strings + !)

There is a rough logic to it: annotations that make a per-invocation decision take SpEL (which user? which cache key? is this expression true right now?). @Transactional's attributes are resolved once when the proxy is built, so there's nothing to evaluate per call.

Memory hook: SpEL: @Value, @PreAuthorize, @Cacheable, @ConditionalOnExpression. No SpEL: @Transactional, @Secured, @Scheduled, @Profile.
Q47 · Enabling annotation-driven transactions two invented names

@Configuration + @EnableTransactionManagement

Your answer: @EnableAnnotationTransaction and @AnnotationDrivenTransactionneither exists. Both are built from the right words in the wrong order, which is exactly the shape to distrust.

The pattern is Spring-wide and worth generalising: feature switches are always @EnableXxx on a @Configuration class.

AnnotationSwitches on
@EnableTransactionManagement@Transactional processing
@EnableAspectJAutoProxy@Aspect processing
@EnableCaching@Cacheable and friends
@EnableScheduling@Scheduled
@EnableAsync@Async
@EnableWebMvcMVC infrastructure beans
@EnableJpaRepositoriesSpring Data repository proxies
@Configuration
@EnableTransactionManagement
public class AppConfig {
    @Bean DataSource dataSource() { … }
    @Bean PlatformTransactionManager transactionManager(DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}

What it actually does: registers an infrastructure bean that creates AOP proxies around @Transactional classes. Without it the annotation is inert — no error, just no transactions, the same silent failure as putting @Transactional on a private method.

And in Boot you never write itTransactionAutoConfiguration adds it for you. That's worth knowing as its own fact, because "which of these do you need in a Boot app?" is a stock question.

Memory hook: @EnableXxx on a @Configuration class. If a name doesn't start with @Enable, it isn't a Spring feature switch.
Q36 · Implementing PreparedStatementCreator callbacks · Data clinic §6

Build a PreparedStatement from the Connection you're handed — SQL and parameters

Your answer: you ticked the descriptions of ResultSetExtractor and RowMapper. Those describe reading results. This callback runs before execution.

The clinic covered the three reading callbacks; this is the writing one. Ordered by when they fire:

CallbackWhenGivenReturns
PreparedStatementCreatorbefore executiona Connectiona configured PreparedStatement
PreparedStatementSetterbefore executiona PreparedStatementvoid — just binds parameters
RowMapper<T>after, once per rowa positioned ResultSetT
RowCallbackHandlerafter, once per rowa positioned ResultSetvoid
ResultSetExtractor<T>after, oncethe whole ResultSetT

Why you'd ever need it — the canonical case is capturing a generated key, which the simple update(sql, args…) form can't do:

KeyHolder keys = new GeneratedKeyHolder();
jdbc.update(con -> {
    PreparedStatement ps = con.prepareStatement(
            "insert into employees(name, dept) values(?, ?)",
            Statement.RETURN_GENERATED_KEYS);      // ← needs the Connection in hand
    ps.setString(1, emp.name());
    ps.setString(2, emp.dept());
    return ps;
}, keys);
long id = keys.getKey().longValue();

Two rules shared with every JdbcTemplate callback: do not execute it yourself (duplicate rows on INSERT), and do not close the statement or connection — JdbcTemplate owns the lifecycle.

Memory hook: Creator builds the statement (before) · Setter binds parameters (before) · Mapper/Handler/Extractor read results (after).
Q45 · The benefit of NamedParameterJdbcTemplate #6 and the Data clinic

Named parameters — readability. Nothing more exotic than that.

Your answer: three wrong options ticked, including "it prevents SQL injection automatically". That one is worth dwelling on — it's the most plausible wrong answer on the paper.

Why "prevents SQL injection" is wrong. Both templates use PreparedStatement underneath, so bound parameters are safe in both — the protection comes from prepared statements, not from named parameters. And neither protects you if you concatenate user input into the SQL string:

// unsafe in BOTH templates
String sql = "SELECT * FROM users WHERE name = '" + userInput + "'";

// safe in BOTH — the value is bound, not interpolated
jdbc.query("SELECT * FROM users WHERE name = ?", mapper, userInput);
named.query("SELECT * FROM users WHERE name = :name", Map.of("name", userInput), mapper);

So the difference between the two templates is readability and maintainability only:

JdbcTemplateNamedParameterJdbcTemplate
Placeholder? — positional:name — named
Argumentsvarargs, order mattersMap or SqlParameterSource
With 8 parameterseasy to transpose two silentlyself-documenting

It wraps a JdbcTemplate (reachable via getJdbcOperations()) and translates :name into positional ? before executing — so it is strictly a convenience layer, which is exactly why "required for executing SQL" and "handles all SQL including DDL" are both wrong.

Memory hook: Named parameters buy readability, not safety. Prepared statements prevent injection — in both templates.

③ Spring MVC & REST 3 misses

40% → 57% with no clinic, just review #8's return-types table. Still the weakest topic, but moving.

Q14 · What @RestController is equivalent to #7 and #8

@Controller + @ResponseBody

Your answer: both options containing @SpringBootApplication. That's the application entry point — three annotations about bootstrapping, nothing to do with controllers.

The source is two lines long:

@Target(ElementType.TYPE)
@Controller          // ← makes it a Spring MVC controller bean
@ResponseBody        // ← makes every method write to the response body
public @interface RestController { … }

The consequence is the fork you've now met several times:

Class annotationreturn "list"; means
@Controllera logical view nameViewResolver/WEB-INF/views/list.jsp
@RestControllerthe literal text "list" written to the response body

The practical rule: if a controller must return views from some methods and JSON from others, use @Controller and put @ResponseBody on the individual JSON methods. @RestController is all-or-nothing for the class.

And note @RequestMapping is not part of it — you still declare mappings yourself. That was the fourth distractor.

Memory hook: @RestController = @Controller + @ResponseBody. Not @RequestMapping, and nothing to do with @SpringBootApplication.
Q56 · Valid controller method signatures

@RequestBody is input only — it can never annotate a return type

Your answer: you ticked public @RequestBody MyDataDto getMyData(). You correctly accepted the other three, including the HttpHeaders return type — the genuinely surprising one.

The two annotations are a matched pair pointing in opposite directions:

AnnotationDirectionLegal on
@RequestBodyIN — deserialise the request bodya method parameter
@ResponseBodyOUT — serialise the return valuea method or the return type
@PostMapping("/products")
public @ResponseBody Product create(@RequestBody Product incoming) { … }
//     ^^^^^^^^^^^^^ OUT                ^^^^^^^^^^^^ IN

Why HttpHeaders as a return type is valid — the surprise in this question: Spring MVC's list of supported return types is long, and HttpHeaders is on it, producing a header-only response with an empty body. It's legal but rarely what you want; ResponseEntity<T> gives you status, headers and body and is the idiomatic choice.

Also valid in that question: returning a Map (treated as model attributes under @Controller, serialised to JSON under @ResponseBody), and taking an HttpSession parameter — servlet objects go in as parameters, which is the rule that has now appeared on three consecutive papers.

Memory hook: @RequestBody = input, parameter only. @ResponseBody = output, method or return type. Servlet objects are parameters, never returns.
Q1 · What REST is

REST is interoperable — and stateless, and an architectural style rather than a protocol

Your answer: "REST is Stateful" and "REST is Relative". "Stateful" is the exact inverse of a core REST constraint, and "Relative" isn't a REST concept at all.

The six architectural constraints, which is the list these questions are drawn from:

ConstraintMeans
Statelessthe server keeps no client session — every request carries everything it needs
Client–serverseparate concerns, independently evolvable
Uniform interfacestandard verbs and resource URIs
Cacheableresponses declare their cacheability
Layered systemproxies and gateways can sit in between invisibly
Code on demand (optional)the server may ship executable code

"Style, not protocol" is the other stock answer and worth holding alongside: REST is a set of constraints described by Roy Fielding; HTTP is the protocol it's normally carried over. SOAP, by contrast, is a protocol with a specification, an envelope format and a WSDL contract — which is exactly the comparison these questions are usually building toward.

Interoperability follows from the other constraints: standard HTTP verbs plus self-describing representations (JSON/XML) mean a Python client and a Java server need no shared runtime, stubs or contract-generation step.

Memory hook: REST = architectural style, stateless, uniform interface, cacheable, layered, interoperable. SOAP is the protocol.

④ Spring Core 3 misses

75% — the first time Core has been above 71% in nine attempts. The ceiling is broken.

Q18 · Resolving an autowiring ambiguity taught in review #8

Three separate fixes: @Primary, @Qualifier("cat") on the field, or rename the field

Your answer: under-selected. The field-name fallback is the one people miss — and it's the one review #8 spelled out as the last step of the resolution order.

Two IAnimal beans exist, so injection by type is ambiguous. Spring's resolution order, in full:

StepMechanismIn this question
1match by typetwo candidates — ambiguous
2@Qualifier narrows the candidates@Qualifier("cat") on the field
3@Primary wins among what's left@Primary on Cat or Dog
4@Priority
5injection-point name vs bean namesrename the field to cat or dog
6otherwiseNoUniqueBeanDefinitionException
@Component class Person {
    @Autowired private IAnimal cat;     // bean name "cat" → resolved by step 5
}

Why the wrong option is wrong: @Qualifier("animal") on Dog or Cat names a bean called animal, and no such bean exists — the two beans are named dog and cat (the class name, decapitalised). Note also that @Qualifier is placed at the injection point here, not on the candidate class.

Step 5 is why a constructor parameter called myService quietly picks up the bean named myService — behaviour that looks like magic until you know the fallback exists.

Memory hook: @Qualifier → @Primary → @Priority → injection-point name → exception. Bean names default to the decapitalised class name.
Q57 · @PostConstruct and @PreDestroy behaviour #5, #6, #8

Called once · @PreDestroy runs before destroy() · never for prototypes

Your answer: you ticked "always invoked regardless of the bean's scope". An absolute — and prototypes are the exception that makes it false.

The callback order, both directions. Annotation first, then interface, then the XML/@Bean attribute:

Initialisation (after DI)Destruction (on context close)
1. @PostConstruct1. @PreDestroy
2. InitializingBean.afterPropertiesSet()2. DisposableBean.destroy()
3. @Bean(initMethod = "…")3. @Bean(destroyMethod = "…")

Why prototypes get no @PreDestroy: the container creates a prototype, injects it, hands it over and forgets it — it keeps no reference, so it has nothing to call back on. The caller owns the cleanup. Singletons are held for the context's lifetime, so their destruction callbacks fire on close.

Worth pairing with the constraints from review #8: void return, no parameters, not static, any visibility. Between the two questions you now have the whole contract.

Memory hook: Annotation → interface → init/destroy-method. Once per instance. Prototypes get @PostConstruct but never @PreDestroy.
Q22 · Why Spring is called "lightweight"

No JEE server needed · small modular JARs · low overhead — and it's non-invasive

Your answer: "we don't need any runtime" and "you can't use POJOs in Spring". Both are absolutes, and the second inverts one of Spring's founding selling points.

"Lightweight" is a historical claim, aimed at EJB 2.x, and it means three specific things:

SenseMeaningThe EJB 2.x contrast
Non-invasiveyour classes are POJOs — no framework superclass or interface requiredbeans had to implement javax.ejb.* interfaces
No JEE servera plain servlet container or embedded Tomcat is enoughrequired WebLogic, WebSphere or JBoss
Modular / low overheadsmall JARs, take only what you need; fast startupa full application server per deployment

Where the distractors go wrong. "No runtime at all" is nonsense — you always need a JVM; the claim is about not needing an application server. "You can't use POJOs" is the exact inverse of non-invasiveness. And "you are required to extend a Spring class" describes EJB 2.x, which is precisely what Spring was built to escape.

Notice the shape of both your ticks: an absolute negative ("don't need any", "can't use"). That's protocol eliminator (b) — on a question asking why something is good, options that describe a limitation are usually the distractors.

Memory hook: Lightweight = POJOs (non-invasive) + no JEE server + small modular JARs. It never meant "no runtime".

⑤ Spring Security 1 miss

100% → 75%, but only one miss — and it's a distinction genuinely worth knowing.

Q17 · Bypassing the filter chain entirely invented method

web.ignoring().antMatchers("/public/**")

Your answer: filtersNone() (doesn't exist) and anonymous(). anonymous() is real, but it's the opposite of bypassing — it runs the whole chain and assigns an anonymous identity.

The distinction the question is really testing — bypass versus permit:

web.ignoring()permitAll()
Filter chainnever runsruns in full
Authentication checkednono
CSRF protectionnoneapplied
Security headersnoneapplied
SecurityContextnever populatedpopulated (anonymous)
Intended forstatic assets — CSS, JS, imagespublic endpoints
@Override
public void configure(WebSecurity web) {          // note: WebSecurity, not HttpSecurity
    web.ignoring().antMatchers("/css/**", "/js/**", "/images/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/public/**").permitAll()     // still fully filtered
        .anyRequest().authenticated();
}

The tell is the argument type: web.ignoring() is configured on WebSecurity — the object that decides which requests enter the chain at all — while permitAll() lives on HttpSecurity, which configures the chain's behaviour once a request is inside it.

Real-world advice worth carrying: prefer permitAll(). web.ignoring() strips security headers and CSRF too, so it's genuinely only appropriate for static assets — and Spring Security logs a warning if you use it on anything else. In the modern lambda DSL (Security 5.7+, replacing WebSecurityConfigurerAdapter) the same thing is a WebSecurityCustomizer bean.

Memory hook: WebSecurity.ignoring() = never enters the chain (static assets). HttpSecurity.permitAll() = enters and is allowed (public endpoints).

Your close-the-gap checklist — attempt #9

The 16 facts, one line each
How to get the last two marks — do these, in this order (1) Learn the three Actuator sentences. Everything is enabled except shutdown. Over HTTP only health is exposed; over JMX everything is. The exposure key contains web/jmx, the enablement key doesn't. On this paper that is Q13 and Q15 — exactly the two marks you need, and it's ten minutes. (2) Re-cover the six checklists and the Data clinic. Nine of today's sixteen are in there. That's 45 minutes and no new material. (3) Keep slowing down. You went from 29 to 42 minutes and scored your best result in nine attempts — while still leaving 87 minutes unused and still losing 10 marks to multiple ticks on one-answer questions. Target 60+ minutes next time and read every option as its own true/false. (4) Then, and only then, new material. Lesson 16 · Actuator and Lesson 12 · REST cover Spring Boot (56%) and Spring MVC (57%), your two weakest sections — but neither is needed for the +2.

Where you actually are, after nine attempts

Finished: Testing (100% twice running). Strong: Data 81%, Core 75% — and Core has never been this high. Recovering: MVC 40 → 57 in a day, Security 75% off a 100% base. The work: Spring Boot at 56%, which is mostly Actuator, which is mostly one table.

Your score has moved 58 → 70 → 70 → 73 across four papers while the floor under it rose from 33% to 56%. You are two marks away, and nine of your sixteen misses were things you had already written down. The remaining gap is not knowledge — it's retrieval and pace.

I'm your teacher — ask me anything. The highest-value ask now is "build me an Actuator clinic" — it has cost you marks in four consecutive papers and it's pure recall, the same treatment the Data Management page got. Or say "drill the Actuator table" for a fast round on enabled-vs-exposed, "quiz me on the 16" for this attempt, or "merged round" for all 176 corrected facts from the nine reviews.
← Dashboard ← Review #8 Data Management clinic Lesson 16 · Actuator