Exam Drill #18 · 25 Sep 2026 · 16 to fix · 62 drills

Eighteenth attempt — two marks short, and the reason is one section

44/60 = 73%, against a 76% pass mark. 46/60 was the pass, so you missed it by two questions. After three passes in a row this one breaks the run — and it is not spread evenly. Spring Core went 96% → 61% and supplied nine of the sixteen misses. Every other section is at or near its best: Data 89%, Boot 85%, MVC 80%, Security 100%.
You also took 30 minutes longer than #17 and scored seven marks lower, so this was not haste. It was recall. This page is about Core, about the three questions where you ticked nothing false, and about the eight misses that were already answered on this site.

73%
Pass mark 76% ✗
−7
Marks on #17 (51 → 44)
16
Misses — was 9
9
Of the 16 are Spring Core
2
Marks from a pass
Official result · practice exam

73% — you did not pass this time

76% required to pass · 60/60 answered · 44 correct · time used 1h 14m 45s of 2h 10m
Spring Security 100%▬ 00 misses / 3 Data Management 89%▲ 191 miss / 9 Spring Boot 85%▼ 42 misses / 13 Spring MVC 80%▲ 91 miss / 5 Spring Core 61%▼ 359 misses / 23 Testing 57%▼ 183 misses / 7

The section sizes come out exactly this time. Data 8/9 = 88.9%, MVC 4/5 = 80%, Testing 4/7 = 57.1%, Boot 11/13 = 84.6% and Core 14/23 = 60.9% are the only sizes that produce those percentages with those miss counts and still add up to 60. That leaves Security 3/3.
Core is 23 of the 60 questions — 38% of the paper. It is the one section you cannot let slide, because it is bigger than MVC, Testing and Security put together.

The two marks

46/60 is the lowest pass. You had 44. Three of your sixteen misses had no false tick at all — Q16, Q30 and Q39. On each of those you judged every option you ticked correctly and then stopped before taking the rest. Those three alone would have passed this paper, with 55 minutes still on the clock.

If you had…ScoreResult
Taken every true option on Q16, Q30, Q3947Pass (78%)
…and fixed the eight repeats52+87%
What actually happened4473% — two short

What moved between #17 and #18

Attempt #17Attempt #18Result
Score51/60 (85%)44/60 (73%)−7 · first fail since #14
Misses916+7
Questions with a false tick713+6
Stopped short (no false tick)23+1
Left blank00Held — 60/60 answered, sixth paper running
Spring Core misses19+8
Data + MVC + Security misses62−4
Time44m 22s1h 14m 45s+30m, and −7 marks

Read the two middle rows together. The three sections #17's routine drilled — Data, MVC and the trap shapes — went from six misses to two. The routine works. What it did not cover collapsed. And the extra half hour bought nothing, which tells you these were not careless errors: on the three "stopped short" questions you had all the time in the world and still stopped.

Third paper running: the section you revised goes up, the section you skipped goes down

#17's page ended with a 30-minute routine. Here is exactly what each section got, and what it did next:

SectionTime in #17's routine#17 → #18Misses
Data Management10 min — its own clinic70% → 89%3 → 1
Spring MVC5 min71% → 80%2 → 1
Spring Securitynone needed100% → 100%0 → 0
Spring Bootmixed drill only89% → 85%1 → 2
Testing5 min75% → 57%2 → 3
Spring Coremixed drill only96% → 61%1 → 9

Every section with its own block rose. Every section without one fell. This is the third time the site has recorded it: #16 → #17 (Core and Boot up, the other three down), the mixed practice set (Boot up, MVC and Data down), and now. Your score is tracking which section you revised most recently, not what you know.

The fix is not a better rotation — rotation is the problem. It is a short pass over all six sections before every paper, weighted by section size. Core gets the most minutes not because it is your weakest but because it is 23 of 60 questions. The routine at the bottom of this page is built that way.

And Core is the one section with no clinic page

There is a revision clinic for Data, MVC, Testing, Boot and Security. There is none for Spring Core — the biggest section on the paper. The closest things are two drill pages, Container and Core internals, plus lessons 1–7.

That gap lines up exactly with where the marks went. Ask me to build the Spring Core clinic — see the box at the bottom — and this paper's nine misses become its spine.

Eight of the sixteen were already answered on this site

Two were drilled six days before this paper. One you had previously got right, and the page said so at the time. These eight marks need no new study, only recall.

QTopicAlready on this siteThen → now
Q19Singletons are eager, prototypes are lazy#17's mixed drill, six days before — "Singletons are created eagerly by an ApplicationContext" was a drill answerDrilled as true → ticked "singletons are lazy"
Q41@RequestMapping statements#10 Q37 and #17 Q41 — same question twice alreadyThird time. New false tick each time
Q5Where Spring provides mock objects#10 Q32 — same question, and in that page's hook listTicked RMI again — the identical error
Q23@PostConstruct need not be public#7 — that page says: "you were right to reject must be public — private works"Rejected it correctly → now ticked it
Q39Web-aware-only bean scopes#14, #8, #1, lesson 4Fourth sitting. Stopped short of all three
Q30Why Spring is "lightweight"#9 Q22 — same questionStopped short both times
Q54this() matches the proxy#7's AOP table, mixed set's designator tableTicked "direct implementors only"
Q10What changes the scan base packages#14 Q23, Boot clinicTicked @EnableAutoConfiguration

Q19 is the one to sit with. Six days before this paper you answered a drill that said in plain words that singletons are created eagerly. On the paper you ticked "singleton-scoped beans are lazy-initialized by default". Answering a drill once does not make the fact yours — that is the whole argument for the short six-section pass rather than one deep session.

Where the next marks are

BucketMarksWhat it costs you
The eight repeats8No new material. Q5, Q10, Q19, Q23, Q30, Q39, Q41, Q54
Stopped short on a multi-answer3Q16, Q30, Q39 — this alone is the pass
A stricter rule than Spring actually has4Q6, Q23, Q25, Q57 — the shape drill
AOP designator precision2Q22 (within takes a type pattern), Q54 (this = proxy)
Genuinely new3Q6 (containsBean), Q47 (@MockBean targets), Q57 (nested property paths)

The rows overlap, so don't add them up. Only three of the sixteen were new to you. Thirteen were facts this site has already written down. Get back to 51+ and then past it — the ceiling you showed on #17 is still the real number.

All 16, at a glance

QTopicWhat went wrongThe answer
Q1–4Actuator base path+ /boot/actuatorhttp://localhost:8080/actuator
Q5Where Spring provides mocks+ RMI — 2nd timeEnvironment · JNDI
Q6Checking a bean exists+ hasBean(…) — inventedcontainsBean("productService")
Q10Changing the scan base packages+ @EnableAutoConfiguration@SpringBootApplication · @ComponentScan
Q16Web integration test clientsStopped short — all 3 were trueMockMvc · WebTestClient · TestRestTemplate
Q19Singleton vs prototype init+ "singletons are lazy"Singletons eager · prototypes on demand
Q22Valid pointcut expressions+ within(… throws NPE)within() takes a type pattern only
Q23@PostConstruct requirements+ "must be public"void, no args, any visibility, non-static
Q25AnnotationConfigApplicationContext+ "must be @Configuration"Lite mode works · by type · NoUniqueBeanDefinitionException
Q30Why Spring is "lightweight"Stopped short — 2 were trueNo JEE server · low overhead
Q39Web-aware-only scopesStopped short — 3 were truerequest · session · application
Q41@RequestMapping — which is incorrect+ "can be restricted to one verb" (a true statement)"Defaults to GET only" is the false one
Q47@MockBean on method parameters+ "yes"No — @Target({TYPE, FIELD})
Q51External config + profiles+ "spring.profiles.active inside application-prod is enough"A profile file can never switch on its own profile
Q54this(Interface)+ "direct implementors only"Matches when the proxy is an instance of the type
Q57Nested property finder+ findByAddressWithZipCodefindByAddressZipCode · findByAddress_ZipCode

Jump to a section

⓪ Three trap shapes — 12 drills ① Spring Core — 9 misses (61%) · 14 drills ② Testing — 3 misses (57%) · 8 drills ③ Spring Boot — 2 misses (85%) · 8 drills ④ Spring MVC — 1 miss (80%) · 5 drills ⑤ Data Management — 1 miss (89%) · 5 drills Every hook on one screen Mixed drill — all sections, no headings

⓪ Three trap shapes 8 of the 16 misses

Eight of the sixteen misses are one of three shapes. Recognising the shape is worth more than any single fact, because the shape comes back on every paper.

Shape 1 · Q16, Q30, Q39 stopped short

Three questions, no false tick, three marks — and the pass

On these three you ticked nothing that was wrong. You simply stopped before taking every true option. Q16 had three true clients and you took two. Q30 had two true statements. Q39 had three true scopes. Those three marks are the difference between 44 and 47.

It is the fourth paper in a row with this shape — #16 had three, #17 had two (Q2 was five of five), this one has three. The pattern is always the same: you are right about what you tick, and you tick too few.

QOptionsTrueYou took
Q16532
Q30421
Q39432

The routine, unchanged from #17 because it is still the right one: go down the options and write T or F beside each one on its own, ignoring how many you have marked. Then tick every T. You had 55 spare minutes on this paper; there is no excuse on time.

Memory hook: Judge each option alone, then tick every true one. Don't decide in advance how many answers there "should" be.
Shape 2 · Q6, Q23, Q25, Q57 a stricter rule than Spring has

The option adds a requirement that sounds professional and isn't real

On #17 the traps were real annotations given invented jobs. This paper's traps are invented strictness: a rule that sounds like good practice, dressed up as a framework requirement. All four read like something a careful reviewer would say. None of them is true.

QThe plausible ruleThe truthThe test that exposes it
Q23@PostConstruct "must be public"Any visibility — Spring uses reflectionSpring calls it with ReflectionUtils.makeAccessible. Only void and no-args are hard rules
Q25AppConfig "must be @Configuration"Lite mode works without itBeans still register. What you lose is CGLIB proxying of @Bean calls
Q6context.hasBean(name)No such method — it's containsBeanCould you write the line? It doesn't compile
Q57findByAddressWithZipCodeWith is not a traversal keywordSpring Data would look for a property called addressWithZipCode and fail at startup
Memory hook: "Must be public", "must be annotated", "must be declared" — Spring is usually looser than the option claims. The hard rules are about signatures (void, no args), not about style.
Shape 3 · Q41 polarity flip

"Which statement is incorrect" — you picked a correct one

Q41 asked which statement about @RequestMapping is incorrect. You ticked "@RequestMapping can be configured to map exclusively to a specific HTTP method" — which is perfectly true (method = RequestMethod.GET). The false statement was "maps only to GET by default".

The mechanical fix: when the stem contains not, incorrect, false or except, mark each option T or F first without looking at the question, then pick the odd one out. Do not try to hold the inversion in your head while reading. The explanations for this question type are themselves confusing — the practice engine prints "Incorrect. This statement is correct" — which is exactly why you sort the options before applying the polarity.

Memory hook: On a NOT question, label every option T/F first, then answer the polarity last.

① Spring Core 9 misses · 23 questions · 61%, down from 96%

Nine misses across six different corners of the container: bean lookup, scan configuration, scope initialisation, lifecycle callbacks, context bootstrapping and AOP. None of them is deep. That is what makes the drop a revision problem rather than a knowledge problem.

Q6 · Checking whether a bean exists ticked a false option

containsBean(String) — by name, and there is no hasBean

You ticked context.hasBean("productService"). You correctly rejected beanExists, containsBean(Class) and the getBean(...) != null trick.
CallReal?What it does
containsBean(String name)REAL — BeanFactorytrue if a bean or alias with that name exists, including manually registered singletons
containsBeanDefinition(String)REAL — ListableBeanFactoryDefinitions only — a singleton registered at runtime does not count
getBeanNamesForType(Class)REALHow you check by type: .length > 0
getBeanProvider(Class)REALObjectProvider — getIfAvailable() returns null rather than throwing
hasBean(String)❌ invented—
beanExists(String)❌ invented—
containsBean(Class)❌ no such overloadWould not compile

Why getBean(...) != null is wrong and not merely ugly: getBean never returns null. If the bean is missing it throws NoSuchBeanDefinitionException, so the comparison is dead code that can only blow up.

In real code you would rarely call any of these. Prefer @Autowired(required = false), ObjectProvider<T>, Optional<T> injection, or @ConditionalOnMissingBean. containsBean is framework-level API.

Memory hook: containsBean takes a String. By type it's getBeanNamesForType(X.class).length > 0. hasBean and beanExists don't exist.
Q10 · Changing the scan base packages ticked a false option #14 Q23 · Boot clinic

@ComponentScan and @SpringBootApplication. @EnableAutoConfiguration has nothing to do with scanning.

You ticked @EnableAutoConfiguration. You correctly took both real answers and rejected @Configuration.
AnnotationIts attributesAffects the scan?
@ComponentScanvalue/basePackages, basePackageClasses, includeFilters, excludeFilters, lazyInit, nameGenerator, scopedProxyYes — canonical
@SpringBootApplicationscanBasePackages, scanBasePackageClasses (@AliasFor the two above), plus exclude, excludeName, nameGenerator, proxyBeanMethodsYes — via the aliases
@EnableAutoConfigurationexclude, excludeName — that is allNo — it filters auto-configuration classes
@Configurationvalue, proxyBeanMethods, enforceUniqueMethodsNo
// type-safe and refactor-proof — the marker class pins the package
@SpringBootApplication(
        scanBasePackageClasses = { com.acme.web.Marker.class, com.acme.svc.Marker.class })
public class App { }

The default: the package of the annotated class, and everything below it. That is why the main class belongs in the root package — put it in a sub-package and its siblings are silently invisible. The same default applies in tests, because @SpringBootTest walks up from the test class looking for a @SpringBootConfiguration.

Do not add a separate @ComponentScan beside @SpringBootApplication on the same class — @SpringBootApplication already declares one, and a second declaration overrides rather than adds. Put the attributes on @SpringBootApplication itself.

Memory hook: Scan = @ComponentScan / scanBasePackages. Auto-config = @EnableAutoConfiguration(exclude=…). One picks your beans, the other picks Boot's.
Q19 · Singleton vs prototype initialisation ticked a false option drilled on #17, six days before

Singletons are eager. Prototypes are created on request.

You ticked "singleton-scoped beans are, by default, lazy-initialized" — and also took the option that says the opposite. You correctly rejected "prototypes are eagerly initialized".
singletonprototype
CreatedAt context refresh, before run() returnsOn every getBean / injection point
InstancesOne per containerA new one every request
Opt out@Lazy on the bean, or @ComponentScan(lazyInit = true)@Lazy is meaningless — it is already on demand
@PostConstructYesYes — on every instance
@PreDestroyYes, at close()Never. Spring hands the instance over and forgets it

The nuance the exam leans on: a prototype injected into a singleton is created once, while that singleton is being built — which is why the fourth option ("eagerly initialized only when an instance is needed to satisfy a dependency") is marked true. For a genuinely fresh instance per use you need ObjectProvider, @Lookup, or a scoped proxy.

One precision point: eager pre-instantiation is an ApplicationContext behaviour (preInstantiateSingletons() during refresh()), not a BeanFactory one. A bare DefaultListableBeanFactory is lazy throughout. The exam only ever asks about the context.

Memory hook: Singleton = eager + full lifecycle. Prototype = on demand + no destroy callback. Fail fast at startup is the point of eager singletons.
Q22 · Valid pointcut expressions ticked a false option

within() takes a type pattern and nothing else. Only execution() has a throws slot.

You ticked within(com.udemy..* throws NullPointerException) as valid. You correctly accepted args(Double) and execution(void com..App.get*()).
execution( [modifiers] ret-type [declaring-type.]name(params) [throws ExPattern] )
//            public     void    com.acme.App.  get*()      throws IOException

within( TypePattern )        // that's the whole grammar
within(com.acme..*)                                  // ✅
within(com.acme..* throws NullPointerException)       // ❌ parse error
execution(* com.acme..*(..) throws NullPointerException)  // ✅ the legal way
DesignatorTakesMatches on
execution(…)Full method signature pattern + optional throwsThe method being called — the workhorse
within(…)Type pattern onlyAny join point inside that type or package
args(…)Type listRuntime argument types
this(…) / target(…)One typeThe proxy / the target object
@annotation, @within, @target, @argsAnnotation typeMethod / declaring class / runtime class / argument
bean(…)Bean name patternSpring-only, not in plain AspectJ

Also worth knowing what Spring AOP does not support, since it is a cheap question: call, get, set, initialization, staticinitialization, preinitialization, handler, advice­execution, withincode, cflow, cflowbelow, if. Using one of those throws IllegalArgumentException at startup. Spring AOP is method execution only.

A flag on this question's answer key

The option marked correct as execution(public void com.udemy.spring.course.App.*) has no parameter parentheses, and the parameter pattern is mandatory in the execution grammar — as pasted it would not parse. execution(public void com.udemy.spring.course.App.*(..)) would be fine. Your mark was lost on the within option regardless, so this changes nothing about the score. Don't learn the malformed form.

Memory hook: within = where the code lives (a type pattern). execution = what the method looks like (the only one with throws).
Q23 · @PostConstruct / @PreDestroy requirements ticked a false option you had this RIGHT on #7

void, no parameters, non-static — any visibility

You ticked "they must be public". You correctly took "can only return void" and "must take no parameters", and rejected "they can take parameters". Review #7 says of this exact option: "you were right to reject 'must be public' — private works".
RequirementRuleIf you break it
Return typeMust be voidIgnored / IllegalStateException
ParametersMust take noneThe container has nothing to pass
VisibilityAny — private worksNothing. Spring calls ReflectionUtils.makeAccessible
StaticMust not be staticNot invoked
CountOne per class by conventionSeveral is not a compile error but is not portable
ExceptionsMay declare checked exceptionsA throw from @PostConstruct fails bean creation (BeanCreationException)

Where the annotations come from: javax.annotation on the exam's stack (Spring 5.3 / Boot 2.5), jakarta.annotation from Boot 3. Either way the processor is CommonAnnotationBeanPostProcessor, registered automatically by AnnotationConfigApplicationContext, @ComponentScan and every Boot app — no @EnableAnnotationLifecycle-style switch exists.

The three ways, in the order Spring runs them: @PostConstruct → InitializingBean.afterPropertiesSet() → @Bean(initMethod = "…"). Destruction mirrors it: @PreDestroy → DisposableBean.destroy() → @Bean(destroyMethod = "…").

Memory hook: void, no args, not static. Visibility is not a rule — Spring uses reflection, so private void init() is fine.
Q25 · AnnotationConfigApplicationContext + getBean ticked a false option

Lite mode is real: @Configuration is recommended, not required

You ticked "AppConfig.class must be annotated @Configuration for this to work". You correctly took "retrieved by type" and "multiple beans → exception", and rejected both the auto-close and the new-instance-per-call options.
Full mode — @ConfigurationLite mode — no @Configuration
Beans registeredYesYes
getBean(MyService.class)WorksWorks
Class CGLIB-subclassedYes (unless proxyBeanMethods = false)No
Calling myService() from another @BeanReturns the singletonCreates a second instance
Inter-bean dependenciesMethod calls are fineMust use method parameters

The other three options, each a fact worth holding:

Memory hook: No @Configuration = lite mode = beans yes, proxying no. And a plain context you new yourself never closes itself — SpringApplication.run does.
Q30 · Why Spring is "lightweight" stopped short #9 Q22 — same question

No Java EE server needed and low overhead. Both were true.

You took one of the two true statements. You correctly rejected both invasive claims — "you can't use POJOs" and "you are forced to extend a Spring class".

"Lightweight" means exactly two things, and the exam only ever says these two:

ClaimMeaning
Non-invasiveYour classes stay POJOs. At worst they carry an annotation. No base class, no interface, no container-managed contract — the opposite of EJB 2.x
Low overheadSmall modular jars, and it runs in a plain servlet container like Tomcat. No application server

What "lightweight" never meant: that there is no runtime (there is — the container), that it is small in scope (it is enormous), or that it is faster than alternatives. Review #9 flagged the "no runtime needed" distractor; this paper used the POJO one instead.

Memory hook: Lightweight = POJOs (non-invasive) + no JEE server. Two claims, tick both.
Q39 · Web-aware-only bean scopes stopped short 4th sitting · #1, #8, #14, lesson 4

request, session, application — all three. (And websocket.)

You took two of the three. You correctly rejected "web", which is not a scope. This fact has now been on four review pages and in lesson 4.
ScopeOne instance perNeeds a web context?
singletonContainer (the default)No
prototypeRequest for the beanNo
requestHTTP requestYes
sessionHTTP sessionYes
applicationServletContextYes
websocketWebSocket sessionYes
web❌ does not exist

application vs singleton is the distinction that makes this question non-trivial, and it is why application is the one people leave out. singleton means one per ApplicationContext; application means one per ServletContext, stored as a ServletContext attribute. A single web app can have more than one context (a root context plus a DispatcherServlet child), and then a singleton in each context gives you two instances while an application bean gives one.

Using a short-lived scope inside a singleton needs a scoped proxy: @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS), or @RequestScope / @SessionScope / @ApplicationScope, which are the meta-annotated shortcuts and already set the proxy mode.

Memory hook: Two scopes work anywhere (singleton, prototype). Four need a web-aware context (request, session, application, websocket). There is no "web" scope. application = per ServletContext.
Q54 · this(com.example.service.ServiceInterface) ticked a false option #7's AOP table · mixed set

this() tests the proxy. target() tests the real object.

You ticked "only methods in classes that directly implement ServiceInterface". You correctly rejected the three call-site distractors.
TestsJDK dynamic proxyCGLIB proxy
this(T)The proxy objectthis(Interface) ✅ · this(ConcreteClass) ❌Both ✅ — the proxy is a subclass
target(T)The target (real) objectBoth ✅Both ✅

The one case where they differ is a JDK dynamic proxy asked about the concrete class: the proxy implements ServiceInterface but is not a RealService, so this(RealService) misses while target(RealService) matches. Spring Boot proxies with CGLIB by default (spring.aop.proxy-target-class=true since Boot 2.0), which is why the difference rarely bites in practice and always bites on the exam.

Why none of the "call" answers can be right: Spring AOP has no call() designator at all. It weaves at the proxy, so it only ever sees method execution on the target bean — never the call site, and never a self-invocation from inside the same object.

Memory hook: this = the proxy (what the caller holds). target = the bean inside it. They only diverge for a JDK proxy asked about the concrete class.

② Testing 3 misses · 7 questions · 57%, down from 75%

Seven questions, three missed — the lowest section on the paper in percentage terms, and the second paper running that it has fallen. Five minutes in #17's routine was not enough because the three misses sit in three different corners: what Spring mocks, which clients exist, and where an annotation may be placed.

Q5 · Where Spring provides mock objects ticked a false option #10 Q32 — same question, same wrong tick

Environment and JNDI. Not RMI, not JMX.

You ticked RMI — the identical error you made on attempt #10, where the page's hook list says in so many words: "Spring mocks what it abstracts: Environment, JNDI, the Servlet API. Not RMI, not JMX." You correctly rejected JMX and took both real answers.
AreaMock providedPackage
EnvironmentMockEnvironment, MockPropertySourceorg.springframework.mock.env
JNDISimpleNamingContextBuilderorg.springframework.mock.jndi
Servlet APIMockHttpServletRequest, …Response, MockHttpSession, MockServletContext, MockFilterChain, MockMultipartFileorg.springframework.mock.web
HTTP messagesMockHttpInputMessage, MockClientHttpRequest/Responseorg.springframework.mock.http
RMInone—
JMXnone—

The rule that generates the answer: Spring mocks what it abstracts over. It has its own Environment abstraction, its own JNDI lookup support and its own servlet-API-facing web layer, so it ships fakes for all three. RMI and JMX are JVM/network facilities Spring merely integrates with — testing those means using the real thing.

Small footnote for currency: SimpleNamingContextBuilder is deprecated from Spring 5.2 in favour of third-party JNDI simulators. It is still the right exam answer on the 5.3 syllabus.

Memory hook: Spring mocks what it abstracts: Environment, JNDI, the Servlet API. Not RMI, not JMX. You have now met this question twice — make it stick.
Q16 · Clients for a web integration test stopped short

All three: MockMvc, WebTestClient, TestRestTemplate

You took two of the three and ticked nothing false — you rejected EjbClient, MBeanClient and RemoteRmiClient, all three invented. Every judgement you made was right. The mark went on the option you left.
ClientReal server?StyleAuto-configured by
MockMvcNo — mock DispatcherServletBlocking, fluent@WebMvcTest, @AutoConfigureMockMvc
WebTestClientOptional — bind to a server, a controller, a context, or MockMvcNon-blocking@WebFluxTest, @AutoConfigureWebTestClient
TestRestTemplateYes — needs a portBlocking@SpringBootTest(webEnvironment = RANDOM_PORT / DEFINED_PORT)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureWebTestClient
class UserApiIT {
    @Autowired WebTestClient web;      // non-blocking, real port
    @Autowired TestRestTemplate rest;  // blocking, real port, never throws on 4xx/5xx

    @Test void getUser() {
        web.get().uri("/users/1").exchange().expectStatus().isOk();
        rest.getForEntity("/users/1", User.class);   // relative URL — the port is filled in
    }
}

Two properties of TestRestTemplate the exam likes: it is fault-tolerant — it never throws on a 4xx/5xx, it returns the status in the ResponseEntity, which is the opposite of RestTemplate — and it does not follow redirects by default. It is also not registered at all under the default webEnvironment = MOCK, because there is no port to talk to.

And MockMvc's limit: no real container, so anything outside Spring's own filter chain — a servlet container valve, a listener, real HTTP parsing — is never exercised. That is the trade you make for the speed.

Memory hook: No server = MockMvc. Real port = TestRestTemplate. Either way = WebTestClient. Three real clients — tick all three.
Q47 · @MockBean on method parameters ticked a false option

No. @Target({TYPE, FIELD}) — class level or field, never a parameter.

You ticked "yes". This was a two-option question, so there was nothing else to reject.
@MockBean (Spring Boot)@Mock (Mockito)
TargetsTYPE, FIELDFIELD, PARAMETER
On a test method parameterNo — won't compileYes, with MockitoExtension
In the Spring contextYes — replaces the real beanNo — a plain object
Use forIntegration tests with a contextUnit tests without one
@SpringBootTest
class OrderServiceTest {

    @MockBean OrderRepository repo;   // ✅ field — replaces the bean in the context
    @Autowired OrderService service;

    @Test void cancels(@MockBean Clock clock) { }   // ❌ does not compile
    @Test void cancels(@Mock Clock clock) { }       // ✅ with @ExtendWith(MockitoExtension.class)
}

Two more things about @MockBean worth a mark: it is @Repeatable, so the class-level form can be stacked; and it resets the mock after every test method (MockReset.AFTER). Because it changes the bean definitions, each distinct set of @MockBeans produces a separate cached context — which is the usual reason a test suite suddenly starts several contexts.

Currency footnote: from Boot 3.4, @MockBean is deprecated in favour of @MockitoBean. The exam is on Boot 2.5, so @MockBean is the answer.

Memory hook: @MockBean = class or field, in the context. @Mock = field or parameter, no context. Parameters are Mockito's trick, not Boot's.

③ Spring Boot 2 misses · 13 questions · 85%

Thirteen questions and two misses — Boot held up. Both misses are configuration mechanics rather than concepts.

Q1–4 · The Actuator base path ticked a false option

http://localhost:8080/actuator

You ticked http://localhost:8080/boot/actuator. You correctly rejected /bootactuator and /endpoint/actuator.
SettingDefaultEffect
management.endpoints.web.base-path/actuatorSet to /manage and every endpoint moves under it
management.endpoints.web.exposure.includehealth only (Boot 2.5+; info,health up to 2.4)* exposes all; or list them
management.endpoints.web.exposure.excludeemptyWins over include
management.endpoint.<id>.enabledtrue (except shutdown)Enabled ≠ exposed — two independent switches
management.endpoints.web.path-mapping.<id>the endpoint idRenames one path, e.g. health → healthcheck
management.server.portthe app portMove Actuator to its own port; the base path then applies there

Enabled versus exposed is the distinction most Actuator questions turn on. Nearly every endpoint is enabled by default (so its bean exists and JMX can see it) while only health is exposed over HTTP. "I added the starter and /actuator/metrics 404s" is not a bug — it is exposure.include.

Memory hook: /actuator, one segment, configurable via management.endpoints.web.base-path. Only health is web-exposed by default.
Q51 · External config files and profiles ticked a false option Boot clinic · lesson 5

A profile-specific file cannot activate its own profile — since 2.4 it is a startup failure

You ticked "adding spring.profiles.active=prod to application-prod.properties would be enough". You correctly took all four true statements and rejected the spring.config.location distractor — five of six right on a six-option question.

The chicken-and-egg: Boot decides which profiles are active before it reads profile-specific files, and it reads application-prod.properties only once prod is already on. Since Boot 2.4 it does not even fail silently — spring.profiles.active, spring.profiles.include and spring.profiles.default inside a profile-specific document raise InvalidConfigDataPropertyException and the application does not start.

# ✅ from outside the file
java -jar app.jar --spring.profiles.active=prod
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
# ✅ in the NON-profile-specific application.properties
spring.profiles.active=prod
# ❌ in application-prod.properties → InvalidConfigDataPropertyException
Default search locationInside the jar?Wins over
classpath:/Yes—
classpath:/config/Yesthe row above
file:./Noboth classpath rows
file:./config/Noeverything above — this is where Q51's file lives
file:./config/*/Noeverything above

So no extra setting was needed — ./config/ is already searched, and "the current working directory" means the directory you launched from, not the directory holding the jar. Two independent overrides then stack: profile-specific beats plain, and outside the jar beats inside.

PropertyEffectWhere it may be set
spring.config.locationReplaces the default locationsCommand line, system property or env var — not in application.properties
spring.config.additional-locationAdds to them
spring.config.importPulls in a specific extra documentInside a properties/YAML file — this one is fine
Memory hook: A profile file can't switch on its own profile — that's a startup error since 2.4. ./config/ is searched by default. location replaces, additional-location adds.

④ Spring MVC 1 miss · 5 questions · 80%, up from 71%

MVC improved after its five minutes in the routine. The one miss is a question you have now met three times.

Q41 · Which @RequestMapping statement is incorrect ticked a false option 3rd time · #10 Q37 · #17 Q41

Bare @RequestMapping maps every HTTP verb — that is the false statement

You ticked "@RequestMapping can be configured to map the annotated method exclusively to a specific HTTP method", which is true — so it cannot be the answer to a "which is incorrect" question. You correctly rejected the two statements about arrays of paths and class/method placement.

The three previous sittings each had a different false tick, which tells you the fact is not the problem: the polarity is. On #10 and #17 you missed it too.

StatementTrue?
Maps only GET unless method is givenFALSE — the answer. It maps GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE
Accepts multiple paths — @RequestMapping({"/a","/b"})True
Can be narrowed with method = RequestMethod.GETTrue
Works at class and method levelTrue — the only mapping annotation that does both

The full narrowing set: path/value, method, params, headers, consumes, produces, plus name. The shortcuts @GetMapping, @PostMapping, @PutMapping, @DeleteMapping and @PatchMapping are @Target(METHOD) only — a class-level mapping must be @RequestMapping. Class and method paths concatenate.

Why the default matters in production, not just on the exam: a bare @RequestMapping("/admin/delete") answers a GET as happily as a POST. That is an accidental attack surface, and the reason the shortcuts exist.

Memory hook: Bare @RequestMapping = every verb. And on a "which is incorrect" question, label all four T/F first, then pick the odd one out.

⑤ Data Management 1 miss · 9 questions · 89%, up from 70%

The biggest improvement on the paper: 70% → 89%, three misses down to one, after ten minutes on the Data clinic. This is the proof that the routine works.

Q57 · Filtering by a nested property ticked a false option

findByAddressZipCode(…) or findByAddress_ZipCode(…)

You ticked findByAddressWithZipCode. You correctly took both real forms and rejected findByAddress@ZipCode.

How Spring Data resolves …ByAddressZipCode: it first tries the whole thing as one property (addressZipCode); failing that it splits at camel-case boundaries from the right — addressZip.code, then address.zipCode — until a path resolves. An underscore pins the boundary yourself and skips the guessing.

public interface PersonRepository extends JpaRepository<Person, Long> {
    List<Person> findByAddressZipCode(ZipCode zip);    // camel-case traversal
    List<Person> findByAddress_ZipCode(ZipCode zip);   // explicit boundary
}

Why With could never work — and the adjacent fact worth a mark: everything between the subject keyword (find, read, get, query, stream, count, exists, delete) and By is free text and ignored — so findWithZipCodeByAddress(…) is legal and means the same as findByAddress(…). But after By, every word must be a property name or a recognised keyword. With is neither, so findByAddressWithZipCode looks for a property called addressWithZipCode, doesn't find it, and the application fails at startup — not at query time.

The exception to "ignored": Distinct, First and Top are read in that gap — findDistinctTop3ByAddressZipCode(…).

Memory hook: Camel case walks the path; _ pins the boundary. Before By, words are decoration. After By, every word must be a property or a keyword — or it's a startup failure.

Every hook on one screen

The sixteen facts, in one pass

Mixed drill — all sections, no headings

Ten questions with no topic label to prime you. Judge each option on its own, then tick every true one. Where the stem is negative, sort the options first and apply the polarity last.

The change to make before the next attempt (1) Stop rotating. Three papers now show the same thing: the section you revised rises, the section you skipped falls. Six short passes beat one deep one. (2) Weight by section size, not by weakness. Core is 23 of 60. It earns the most minutes even when it is at 96%. (3) Take every true option. Q16, Q30 and Q39 had no false tick between them. Three marks. That was the pass. (4) Distrust "must". "Must be public", "must be @Configuration" — Spring is looser than the option claims. The hard rules are about signatures. (5) On a NOT question, sort first. Label all options T/F, then apply the polarity. Q41 is now three for three against you. (6) Time is not the constraint. You used 1h 15m of 2h 10m and still stopped short on three questions.
A 35-minute routine before the next paper — all six sections, weighted by size 12 min — Spring Core. Fourteen drills. It is 23 of 60 questions; treat it as non-negotiable every single time. 5 min — the shape drill. Twelve statements: stopped short, invented strictness, polarity. 5 min — Testing. Eight drills: the mocks, the three clients, @MockBean's targets. 5 min — Spring Boot. Eight drills: Actuator exposure and config locations. 3 min — MVC + Data. Ten drills. Both are healthy — keep them warm. 5 min — the mixed drill. No headings, so nothing primes you. Plus 2 min — Security. 100% for four papers running. Don't be the one who lets the safe section slip.
I'm your teacher — ask me anything. The single most useful thing you can ask for right now: say "build the Spring Core clinic". Every other section has one; Core does not, and Core is where seven of your last eight lost marks came from. I'll build it from this paper's nine misses plus every Core miss across eighteen papers. Or say "drill the repeats" for a set from every question you have missed more than once — Q41 is now three-for-three, and Q39 four-for-four. Or "quiz me on the 16" for this attempt only.
← Dashboard ← Review #17 Core internals drill Container drill Testing clinic Boot clinic