Exam Review #4 · 18 Aug 2026 · 17 to fix

Fourth attempt — 72%. Three questions from a pass.

You scored 43 / 60 = 72%+6 marks on attempt #3 and your best yet. Pass is 76% (46/60), so you are +3 questions away. And the story is unambiguous: every section you revised went up — Security 33% → 100%, Data 60% → 91%, Boot 45% → 78%. The two you didn't re-drill went down. The method works; point it at Spring Core and Spring MVC.

72%
This attempt (43/60)
62%
Attempt #3 (37/60)
76%
Pass mark (46/60)
+3
Questions to pass
Official result · practice exam

72% — you did not pass this time

76% required to pass · 60/60 answered · 43 correct · time used 51m 21s of 2h 10m
Spring Security 100%▲ 670 misses Data Management 91%▲ 311 miss Spring Boot 78%▲ 332 misses Testing 73%▼ 103 misses Spring Core 62%▼ 68 misses Spring MVC 57%▼ 33 misses

How to read this. Four sections are now at or near pass standard. Spring Core is the whole problem: 8 of your 17 misses, and it's the biggest section on the blueprint, so 62% there caps your total score no matter what else you do. Spring MVC at 57% is second — only 3 raw marks, but it's the lowest percentage on the sheet and two of those three were the same @RestController question in different clothes. Fix Core + MVC and you're through.
And the timing. 51m 21s of 2h 10m — you used 39% of your time, faster still than last attempt's 1h 15m. That is roughly 51 seconds per question. Five of these 17 were multi-selects where you left a correct option unticked — the exact failure mode that an unhurried second read fixes. You have 79 minutes of unused time to spend on that.

Trend: 39 → 40 → 37 → 43. The first real break in the pattern, and it isn't luck — it maps directly onto what you revised after review #3. Security, Data and Boot were the three topics that review told you to close, and they came back at 100%, 91% and 78%. Core and MVC were left alone and drifted down. You now need 3 more questions. There are 8 sitting in Spring Core alone.
The one habit costing you the most: you under-select on "select all that apply"

The 17 questions you failed

Your answer is reconstructed from the exported result — if any line looks wrong to you, tell me and I'll correct it. Click the topic to jump to the full fix.

QTopicWhat you answeredThe answer
Q10Controller return typesUnder-selected — missed one of the valid typesvoid, String, ModelAndView (not HttpServletRequest)
Q13@WebMvcTest — which is NOT correct"@WebMvcTest auto-configures MockMvc"None of the above (all three were true)
Q15Setting the SpEL compiler mode"Through a Maven SpEL plugin"SpelParserConfiguration + the spring.expression.compiler.mode system property
Q25Adding a bean definitionUnder-selected — likely missed registerBeanDefinitionXML <bean/>, @Bean method, DefaultListableBeanFactory.registerBeanDefinition
Q27JPA query method names"deleteAgeLessThan(int age)"findByLastName, countByAgeGreaterThan
Q32Stereotypes found by scanningUnder-selected — all four were correct@Controller, @RestController, @Repository, @Service
Q33Precedence between two advices"None of the above, we can't control that"@Order
Q37SpEL compiled-mode limitsUnder-selected — missed one of the fourassignment, custom resolvers/accessors, conversion service, selection/projection
Q38@RestController returning String"automatically returns the response in JSON"@RestController = @Controller + @ResponseBody; @GetMapping maps GET /greeting
Q39Injecting the Actuator port"@LocalPort"@LocalManagementPort and @Value("${local.management.port}")
Q40Request-processing lifecycle"returns a view name resolved to a template"@GetMapping maps the URL; @RestController applies @ResponseBody to all methods
Q44@Autowired method, unresolvable paramUnder-selected — missed one of the threeException + method skipped; per-param Optional/@Nullable; method-level required=false
Q45MockMvc in @SpringBootTest"Nothing, it's configured by default"Add @AutoConfigureMockMvc
Q46Spring/Boot testing facts"spring-test provides @Mock and @MockBean"Integration + slice testing supported; @SpringBootTest or @SpringJUnitConfig create the context
Q52Monitoring method duration"Use a gauge"Use a Timer
Q53@AliasFor"declares an alias for a bean"Declares aliases for annotation attributes
Q58@Transactional supports SpEL?"True"False — @Transactional has no SpEL support
Repeat offenders — topics that have now hit you across multiple attempts @Order (attempts #2, #3 and #4 — three different angles) · ways to register a bean definition (#3 Q11 → #4 Q25) · @RestController / @ResponseBody (#3 Q14 → #4 Q38 and Q40) · Micrometer meter types (#3 Q28 gauge → #4 Q52 timer) · @WebMvcTest (#2 twice → #4 Q13). Each has a consolidated table below — these are the ones to over-learn, because the exam clearly likes them.

Jump to a section

① Spring Core — 8 misses ② Spring MVC — 3 misses ③ Testing — 3 misses ④ Spring Boot & Actuator — 2 misses ⑤ Data Management — 1 miss

① Spring Core 8 misses

Half your losses, and the section that caps your score. Two clusters here: SpEL internals (Q15, Q37) and container fundamentals you've now missed twice (Q25, Q32, Q33).

Q15 · Setting the SpEL compiler mode

Two ways: SpelParserConfiguration, or the spring.expression.compiler.mode system property

Your answer: "Through a Maven SpEL plugin" — no such plugin exists. Correct: SpelParserConfiguration + the system property.

SpEL normally interprets the expression AST on every evaluation. The compiler turns a hot expression into real bytecode. You switch it on either programmaticallynew SpelParserConfiguration(SpelCompilerMode.MIXED, classLoader) passed to a SpelExpressionParser — or JVM-wide with -Dspring.expression.compiler.mode=IMMEDIATE|MIXED|OFF, which sets the default used for framework expressions (@Value, @Cacheable …). SpEL is a runtime parser, so there is no build plugin and no JMX surface — both were invented distractors.

The three modes: OFF (default — always interpret) · IMMEDIATE (compile on first evaluation; if the runtime types later differ it fails fast and you must handle it) · MIXED (interpret first, compile in the background after N successful runs, and silently fall back to interpreting on a type mismatch). The two configuration routes are independent — your own parser instance always wins for that parser.

Memory hook: Config object or -D property. OFF default · IMMEDIATE fails fast · MIXED falls back.
Q37 · What compiled SpEL can't do

No assignment, no custom resolvers, no conversion service, no selection/projection

Your answer: under-selected — you ticked only some of the four. All four of those are unsupported; operators and constructors are supported.

Learn it as two short lists. Not compilable: assignment (name = 'John') · expressions using custom PropertyAccessor/MethodResolver (runtime dispatch can't be compiled) · anything relying on the ConversionService for coercion · collection selection .?[…] and projection .![…]. Compilable (the two you must not tick): ordinary operators (+ - * / == < >) and constructor calls (new com.example.Foo()).

Memory hook: Static and simple compiles. Anything dynamic — assignment, custom resolvers, conversion, ?[ ] and ![ ] — does not.
Q25 · Adding a bean definition 3rd attempt, 2nd miss

XML <bean/> · @Bean method · registerBeanDefinition(...) — and there is no @BeanComponent

Your answer: under-selected — you almost certainly skipped the programmatic DefaultListableBeanFactory.registerBeanDefinition. You correctly avoided the invented @BeanComponent.

This is the second time this topic has taken a mark (attempt #3 Q11). Learn the whole list once and it can never cost you again:

MechanismLooks likeNotes
XML<bean id="x" class="com.X"/>read by XmlBeanDefinitionReader
@Bean methodin a @Configuration classreturn value becomes the bean
Stereotype + scanning@Component + @ComponentScanthe @Component defines it; the scan only finds it
ProgrammaticbeanFactory.registerBeanDefinition(name, bd)the one you keep missing — DefaultListableBeanFactory
BeanDefinitionRegistryPostProcessorhook at startupdynamic registration
@Importconfig class or ImportBeanDefinitionRegistrarhow Boot's own starters register beans

Invented annotations to reject on sight: @BeanComponent, @BeanDefinition, @Register. The real stereotypes are only @Component, @Service, @Repository, @Controller (+ @RestController, @Configuration).

Memory hook: XML · @Bean · @Component+scan · registerBeanDefinition · registry post-processor · @Import. Six routes.
Q32 · Stereotypes discovered by scanning

All four were correct — @Controller, @RestController, @Repository, @Service

Your answer: under-selected — there was no wrong option to avoid here. Every option was a genuine stereotype. When the whole option set comes from one family, "all of them" is usually right.

Every stereotype is meta-annotated with @Component, which is exactly why component scanning finds them:

AnnotationLayerExtra behaviour beyond @Component
@Componentgenericthe base stereotype
@Controllerwebenables handler mapping
@RestControllerweb@Controller + @ResponseBody
@Servicebusinessnone — a semantic marker only
@Repositorydataexception translation to DataAccessException
@Configurationconfigalso a @Component; CGLIB-proxied for inter-@Bean calls
Memory hook: @Repository translates exceptions · @Controller maps handlers · @Service does nothing special. All are @Component underneath.
Q33 · Ordering two advices at one join point @Order, 3rd appearance

@Order (or the Ordered interface) — lower value runs first

Your answer: "None of the above, we can't control that"you can: put @Order on the aspects.

When two aspects advise the same join point, precedence is undefined unless you set it. @Order(1) on SecurityAspect and @Order(2) on LoggingAspect makes security run first (lower = higher priority). @Precedence doesn't exist; @Primary is about injection, not advice. Note the ordering is between aspects — two advices of the same type inside one aspect still have undefined order, so split them. (AspectJ's own @DeclarePrecedence exists but isn't what Spring's exam wants here.)

@Order has now appeared in three consecutive attempts, each time meaning something different. Learn the whole map — this is your single highest-value table:

Where @Order is usedWhat it controlsAttempt
On two aspects at the same join pointadvice execution order — lower first#4 Q33
On @Configuration classesthe order configs are processed#3 Q25
On beans injected into a List<T>position in the list
On filters / interceptorsposition in the chain
What @Order never does: it does not change when the container instantiates a bean (that's @DependsOn / @Lazy — attempt #2 Q38), and it does not decide which bean wins injection (that's @Primary / @Qualifier).
Memory hook: @Order = position in a sequence (advice, configs, lists, filters). Never creation, never winning.
Q44 · @Autowired method with an unresolvable parameter

Three true behaviours — and the difference between method-level and parameter-level optionality

Your answer: under-selected — you missed one of the three true statements. You correctly rejected the fictional @TryInvoke.

Spring resolves all parameters of an @Autowired method against the BeanFactory. What happens when one can't be resolved depends on where you declare the optionality:

DeclarationBehaviour when a param is missing
Plain @Autowired (default)Exception (NoSuchBeanDefinitionException) and the method is not invoked
@Autowired(required = false) on the methodNo exception; the whole method is skipped
Optional<T>, @Nullable or required=false on a parameterMethod is still invoked; that param gets null/Optional.empty()

The exam loves that middle-versus-bottom distinction: method level = skip the call, parameter level = call it with a hole in it. (Constructors differ — use Optional<T> parameters for optional constructor dependencies.)

Memory hook: required=false on the method ⇒ never called. @Nullable on a param ⇒ called with null.
Q53 · @AliasFor

It aliases annotation attributes — nothing to do with beans

Your answer: "it can be used to declare an alias for a bean"no: it declares aliases for attributes of an annotation.

@AliasFor (in org.springframework.core.annotation) makes two attributes of an annotation interchangeable — set either one and both carry the same value; setting both to different values is an error. It's how @RequestMapping's value/path, and @SpringBootTest/@WebMvcTest's value/controllers, work.

public @interface MyAnnotation {
    @AliasFor("location") String value()    default "";
    @AliasFor("value")    String location() default "";
}

Bean aliases are a different feature entirely: XML <alias name="a" alias="b"/>, or extra names in @Bean(name = {"primary", "alias"}).

Memory hook: @AliasFor = annotation attribute ↔ attribute. Bean aliases = @Bean(name={...}).
Q58 · Does @Transactional support SpEL?

No. Its attributes take fixed types only

Your answer: Truethe answer is False.

@Transactional's attributes — propagation, isolation, timeout, readOnly, rollbackFor, transactionManager — accept enums, ints, booleans and classes. None of them is SpEL-evaluated. Learn the annotations by which side of that line they sit on:

AnnotationSpEL?Where
@Valueyes#{...} expressions (and ${...} placeholders)
@PreAuthorize / @PostAuthorizeyesthe whole security expression language
@Cacheable / @CacheEvictyeskey, condition, unless
@ConditionalOnExpressionyesBoot auto-config conditions
@Transactionalnofixed-type attributes only
@Scheduledno${...} property placeholders only
Memory hook: Security, caching and @Value speak SpEL. Transactions and scheduling do not.

② Spring MVC 3 misses

Your lowest percentage (57%). Two of the three were the same @RestController question asked twice — so one fact is worth two marks here.

Q10 · Valid controller return types

void, String, ModelAndViewHttpServletRequest is a parameter, never a return type

Your answer: under-selected — you avoided the trap but didn't tick all three valid types.

Valid returns: void (you wrote the response yourself, or 204 No Content with @ResponseBody) · String (a view name — or the literal body under @ResponseBody) · ModelAndView (view + model together) · a domain object / collection (serialised by an HttpMessageConverter) · ResponseEntity<T> (body + status + headers — the production choice) · also Callable, DeferredResult, Model, View, HttpEntity. Not valid: HttpServletRequest / HttpServletResponse — those are injected into parameters.

Memory hook: Request/Response objects go IN as parameters. Views, models, bodies and entities come OUT.
Q38 & Q40 · @RestController returning a String also missed in #3

A String from a @RestController is text/plain — not JSON, not a view name

Q38 — your answer: "the method automatically returns the response in JSON format". Q40 — your answer: "the method returns a view name resolved to a template". Both wrong in opposite directions: the String is the body, written as plain text.

Nail the mapping from return type to content type — it converts two misses into two marks:

Return type in a @RestControllerContent-TypeConverter
Stringtext/plainStringHttpMessageConverter
POJO / List<T>application/jsonMappingJackson2HttpMessageConverter
ResponseEntity<T>depends on the body+ custom status & headers
byte[]application/octet-streamraw bytes

The rest of both questions comes from one sentence: @RestController = @Controller + @ResponseBody on every method. Therefore: no view resolver is involved · adding @ResponseBody per method is redundant · the return value is never a view name · and @EnableWebMvc is not required in Boot (auto-configuration handles it — in fact adding @EnableWebMvc disables Boot's MVC auto-configuration, a classic own goal). Also true: @GetMapping("/x") is exactly @RequestMapping(value="/x", method=GET).

The lifecycle to recite (Q40's real subject): request → DispatcherServlet (front controller) → HandlerMapping (URL → method) → HandlerAdapter (invokes it, applies @ResponseBody) → HttpMessageConverter writes the body → ViewResolver only if there's no @ResponseBody. @RestController skips that last step entirely.

Memory hook: @RestController = @Controller + @ResponseBody. String ⇒ text/plain body. No view resolver, no @EnableWebMvc needed.

③ Testing 3 misses

Q13 · @WebMvcTest — "which is NOT correct" negative stem again

All three statements were true, so the answer was "None of the above"

Your answer: "@WebMvcTest auto-configures MockMvc" — but that is true, so it can't be the incorrect statement. Correct: None of the above.

All three claims hold: @WebMvcTest auto-configures the Spring MVC infrastructure, it is meta-annotated with @ExtendWith(SpringExtension.class), and it auto-configures MockMvc. Review #3 already flagged that negative stems ("NOT", "incorrect") are catching you — and here it cost a mark you had the knowledge to win. Technique: on a "which is NOT" question, mark each option true/false in the margin first, then pick the odd one out. If every option is true, "None of the above" is the answer, not a cop-out.

@WebMvcTest, definitively. Loads: @Controller, @RestController, @ControllerAdvice, @JsonComponent, Converter/Formatter, Filter, WebMvcConfigurer, and MockMvc. Does not load: @Service, @Repository, plain @Component, full auto-configuration, or any datasource/JPA — so collaborators must be supplied with @MockBean.

Memory hook: @WebMvcTest = controllers + MockMvc, no services. And "none of the above" is a real answer.
Q45 · MockMvc inside @SpringBootTest

Add @AutoConfigureMockMvc@SpringBootTest alone does not give you MockMvc

Your answer: "Nothing, MockMvc is configured by default with @SpringBootTest"that's true of @WebMvcTest, not @SpringBootTest.

@SpringBootTest loads the full context but registers no MockMvc bean. @AutoConfigureMockMvc triggers MockMvcAutoConfiguration, which wires one from the WebApplicationContext — filters, security, error handling and message converters included. (There is no MockMvc.setUp() or MockMvc.create(); the manual route is MockMvcBuilders.webAppContextSetup(wac).build().)

SetupContextHow you call the app
@WebMvcTest(Ctrl.class)MVC slice onlyMockMvc — automatic
@SpringBootTest + @AutoConfigureMockMvcfull context, no serverMockMvc — after you add the annotation
@SpringBootTest(webEnvironment = RANDOM_PORT)full context + real serverTestRestTemplate / WebTestClient

Two exam-worthy details: @AutoConfigureMockMvc(addFilters = false) strips the filter chain (handy to bypass Spring Security), and mixing RANDOM_PORT with MockMvc is contradictory — MockMvc never touches the embedded server. For WebFlux it's @AutoConfigureWebTestClient, since MockMvc is servlet-only.

Memory hook: @WebMvcTest gives you MockMvc free. @SpringBootTest makes you ask — @AutoConfigureMockMvc.
Q46 · Which two testing statements are true

Integration and slice testing are supported; contexts come from @SpringBootTest or @SpringJUnitConfig

Your answer: "The spring-test dependency provides annotations such as @Mock and @MockBean"neither one comes from spring-test.

Know which module owns which annotation — that's the whole question:

AnnotationComes from
@Mock, @InjectMocks, @SpyMockito
@MockBean, @SpyBeanspring-boot-test (not spring-test)
@SpringBootTest, @WebMvcTest, @DataJpaTestspring-boot-test-autoconfigure
@ContextConfiguration, @SpringJUnitConfig, @DirtiesContextspring-test

The other two distractors: Mockito is the default mocking framework (EasyMock needs a manual dependency — not "out of the box"), and spies are fully supported via @SpyBean. Also remember @SpringJUnitConfig = @ExtendWith(SpringExtension.class) + @ContextConfiguration, the plain-Spring way to build a test context.

Memory hook: @Mock = Mockito · @MockBean = spring-boot-test · @ContextConfiguration = spring-test. EasyMock isn't included.

④ Spring Boot & Actuator 2 misses

45% → 78% after review #3. Only two left, and one is a meter type you've now been asked about twice.

Q39 · Injecting the Actuator management port

@LocalManagementPort — or @Value("${local.management.port}")

Your answer: "@LocalPort"that injects the application port (and the real annotation is @LocalServerPort).

By default Actuator shares the app's port; set management.server.port=8081 to split them. Then:

You wantUse
The management (Actuator) port@LocalManagementPortpreferred — or @Value("${local.management.port}")
The application port@LocalServerPort (or @Value("${local.server.port}"))

@LocalManagementPort lives in org.springframework.boot.actuate.autoconfigure.web.server. This matters most in tests using webEnvironment = RANDOM_PORT, where both ports are assigned dynamically. @ActuatorPort and a bare @LocalPort are invented.

Memory hook: Management port = @LocalManagementPort. Server port = @LocalServerPort. Nothing is called just "@LocalPort".
Q52 · Measuring how long a method takes meters again — see #3 Q28

Timer — it records count and total time

Your answer: "use a gauge"a gauge is a point-in-time value; duration is a Timer.

Attempt #3 asked you about gauges; this one asks about timers. Learn the five meters as one block and both questions become free:

MeterMeasuresUse for
Countermonotonically increasing countrequests handled, errors
Gaugecurrent value at read timequeue size, active connections
Timerduration + countmethod / request execution time
DistributionSummarydistribution of valuespayload sizes
LongTaskTimerduration of in-progress taskslong-running jobs

Register it in code, not in application.yml — custom metrics are programmatic: registry.timer("order.processing.time").record(() -> { … }), or annotate the method with @Timed. Timers publish count, totalTime, max and percentiles through /actuator/metrics.

Memory hook: How many? Counter. How much right now? Gauge. How long? Timer.

⑤ Data Management 1 miss

60% → 91%. One question stood between you and a clean sheet.

Q27 · Spring Data query method names

Subject + By + property expressions joined with And/Or

Your answer: deleteAgeLessThan(int age)missing the By; it must be deleteByAgeLessThan.

Spring Data parses the method name as subject (find, read, get, query, count, exists, delete, remove) + By + predicate. Both parts are mandatory:

Method nameValid?Why
findByLastName(String)yessubject + By + one property
countByAgeGreaterThan(int)yescount subject + keyword
findByLastNameFirstName(...)noneeds And: findByLastNameAndFirstName
deleteAgeLessThan(int)nomissing By: deleteByAgeLessThan

Keywords worth recognising: GreaterThan/LessThan, Between, Like/Containing/StartingWith, In, IsNull, Not, IgnoreCase, OrderBy…Asc/Desc, Top/First. Property names must match entity fields — findByLastNameFirstName is parsed as one property lastNameFirstName and, when it doesn't exist, fails at startup, not at call time.

Memory hook: Always a "By". Multiple criteria always joined by And/Or. Bad names break at startup.

Your close-the-gap checklist — attempt #4

The 17 facts, one line each — cover this list from memory before the next go
Do this next — you need 3 marks (1) Exam technique first, it's worth ~5 marks on this paper. On every "select all that apply", go option by option and say true or false out loud before ticking. On every "which is NOT", mark all options first. You had 79 minutes spare — spend 30 of them re-reading stems. (2) Spring Core is 8 of your 17. Re-read Lesson 5 · Properties, Profiles & SpEL (both SpEL misses), Lesson 1 · The container and Lesson 3 · Scanning & @Autowired, then reproduce the @Order map above from memory. (3) Spring MVC is one fact. Lesson 11 + Lesson 12: @RestController returns a body, and String means text/plain. (4) Then retake the Full Mock Exam. Leave Security, Data and Boot alone — they're done.
I'm your teacher — ask me anything. Want a Spring Core blitz (SpEL + container + @Order), a 20-question multi-select technique drill built purely from "select all that apply" items, or a merged round over all 81 misses from the four attempts? Just ask. Say "quiz me on the 17" for this attempt only.
← Review #3 Retake the Mock Exam →