41/60 = 68%, against a 76% pass mark. Five marks short. After two passes in a
row this is a big drop, but it is a narrow one: 13 of the 19 misses are Spring Core, and Core was half the
paper (about 30 questions). Data Management went the other way, from 75% to 100%.
Most of the Core misses are basics: @Autowired, stereotypes, @Bean
attributes, @PostConstruct. And five of the 19 were questions you've already missed on an earlier
paper. Getting just those five right would have scored exactly 46, which is a pass.
The first fourteen papers averaged 40.3. The last seven average 47.1, even with today's 41. Today puts you back at the level of the first fourteen papers, but the misses are concentrated in one section, which is easier to fix than a broad slump.
How the sizes come out. There was no Security section this time. MVC at 33% with two misses can only be 1/3. Testing at 75% is 6/8, and Boot at 80% is 8/10. That leaves 13 misses for Core, and 57% with 13 misses only works as 17/30. Data takes the remaining 9 questions, all correct. MVC's 33% looks alarming, but it's three questions. Core's 57% is the real story: half the paper, and 13 of the 19 lost marks.
| If you had… | Score | Result |
|---|---|---|
| Not repeated the five questions you'd already missed, word for word, on an earlier paper | 46 | 77% — pass |
…and got the three that repeat a topic you've missed before (BPP timing, Environment, proxy types) | 49 | 82% |
…and the five @Autowired / stereotype / @Bean basics | 54 | 90% |
| What actually happened | 41 | 68% — not passed |
The pass needed no new knowledge. The five repeats on their own cover the gap. That's why the repeats block comes first on this page, and why it's worth redoing on a different day.
| Attempt #20 | Attempt #21 | Result | |
|---|---|---|---|
| Score | 50/60 (83%) | 41/60 (68%) | −9 · not passed |
| Misses | 10 | 19 | +9 |
| Questions with a false tick | 9 | 16 | +7 |
| Stopped short (no false tick) | 1 | 3 | +2 · all three were "3 of 4 true" |
| Left blank | 0 | 0 | Held — ninth paper running |
| Spring Core misses | 4 | 13 | +9 — the whole drop |
| Data Management misses | 3 | 0 | −3 · the #20 Data drills held |
| Word-for-word repeats | 5 of 10 | 5 of 19 | Same count, different questions |
| Time | 39m 46s | 57m 57s | +18 min |
The +9 in Core matches the −9 in the score. Every other section moved by a mark or two. You also took 18 minutes longer than on #20, so this doesn't look like rushing. More likely, more of Core's questions felt uncertain this time.
| Q | Topic | Already on this site | Then → now |
|---|---|---|---|
| Q57 | @PostConstruct / @PreDestroy constraints | #7 Q27, word for word, and #18 Q23, reworded | Ticked "must be public" all three times |
| Q20 | When Load-Time Weaving changes bytecode | #13 Q60, reworded | Ticked "at runtime through JDK/CGLIB proxies" both times |
| Q5 | Customising the embedded server | #8 Q23, word for word | Ticked "exclude Tomcat, add Jetty = external server" both times, plus server.timeout this time |
| Q33 | The class that applies @Transactional advice | #15, word for word | Then: invented TransactionStatusAdvice. Now: invented PlatformTransactionManagerAdvisor |
| Q39 | What @MockBean does | #11 Q11, same options | Stopped short of the three true options both times |
| Q43 | When a BeanPostProcessor runs | #14 Q29 and #19 Q2, same topic | Third paper on BPP timing. Then "only once"; now "before instantiation" |
| Q45 | What Environment exposes | #14 Q27, the non-web twin | Then gave JNDI + servlet params to a non-web app. Now: invented "System Registry" |
| Q12 | CGLIB vs JDK proxy limits | #13 Q24, same topic | Then gave JDK proxies CGLIB's limits. Now gave CGLIB the JDK's interface rule |
Q57 is now a three-time miss with the same wrong click. Two review pages have explained it, so reading isn't fixing it. What should help is answering the question again, correctly, on a different day. The first drill block has all eight, as they appeared on the paper.
Each time you finish a drill block (every question answered), it's recorded here in this browser. Reload the page to retake a block. Questions and options reshuffle every time. Aim for a full score on every block before the next paper. Do the three Core blocks first, and redo the repeats block on a different day from the first try.
| Drill block | Qs | Last | Best | Runs | Last done |
|---|---|---|---|---|---|
| Loading… | |||||
| Q | Topic | What went wrong | The answer |
|---|---|---|---|
| Q5 | Customising the embedded server | + server.timeout · + Jetty = "external" · same as #8 | WebServerFactoryCustomizer · server.port |
| Q10 | Valid @Autowired forms | + searchBy="type" | Setter (Map) · constructor · array field |
| Q12 | CGLIB limitations | + "must implement an interface" | Self-invocation · final class · final methods |
| Q20 | When LTW changes bytecode | + "via JDK/CGLIB proxies" · same as #13 | When a classloader loads the class |
| Q28 | @Autowired on a private field | + "by type, setter methods only" | Injects by type, private fields too |
| Q29 | Properties of REST | + Resilience | Statelessness · scalability |
| Q30 | BFPP — which is incorrect? | + "applies transformations to bean definitions" (a true statement) | "Its only method is postProcess()" |
| Q32 | Which is not a stereotype? | + @Configuration | @Autowired |
| Q33 | Class in the tx AOP proxy | + PlatformTransactionManagerAdvisor · repeat of #15 | TransactionInterceptor |
| Q34 | Circular setter injection | + "always throws" | Early reference to a partly built bean |
| Q37 | Controller argument annotations | Stopped short — 3 were true | @RequestParam · @PathVariable · @RequestBody |
| Q39 | @MockBean | Stopped short — 3 were true · same as #11 | Class or field · adds mocks · can define a new bean |
| Q43 | When BPP modifies beans | + "before instantiation" · 3rd BPP paper | Before (and after) initialisation |
| Q45 | Environment in a web app | + "System Registry Properties" | Servlet context · servlet config · JNDI |
| Q47 | Adding auto-config to a test | + @ContextConfiguration | @ImportAutoConfiguration |
| Q50 | Why not field injection | + "harder to read" | Breaks encapsulation · harder to test |
| Q56 | Excluding auto-configuration | + @ComponentScan(excludeFilters) | exclude · excludeName · spring.autoconfigure.exclude |
| Q57 | @PostConstruct constraints | + "must be public" · 3rd time | Returns void · no parameters |
| Q60 | What @Bean can set | Stopped short — 3 were true | Name · init method · destroy method |
@Autowired — 6 misses · 12 drills
①c Core: lifecycle + container hooks — 4 misses · 9 drills
② Spring Boot — 2 misses (80%) · 6 drills
③ Testing — 2 misses (75%) · 6 drills
④ Spring MVC — 2 misses (33%) · 5 drills
Every hook on one screen
Mixed drill — all sections, no headings · 10 drills
| Q | The tempting option | Why it feels right | What rules it out |
|---|---|---|---|
| Q57 | @PostConstruct must be public | The container has to call it from outside | The container calls it by reflection, which ignores visibility. Same reason @Autowired works on a private field |
| Q20 | LTW happens "at runtime through proxies" | Load time is runtime, and Spring AOP is runtime | A proxy is a separate object. Weaving changes the class's own bytes, which happens as the classloader reads them |
| Q5 | Swap Tomcat for Jetty = external server | "Exclude Tomcat" sounds like "remove the embedded server" | Jetty is also embedded. External = WAR + SpringBootServletInitializer |
| Q33 | A …Advisor / …Advice class | AOP vocabulary is all advice and advisors | The class is an interceptor: TransactionInterceptor, a MethodInterceptor |
| Q39 | Stopping at two | "Defines a new bean" sounds wrong for a mock | If no bean of that type exists, @MockBean adds one. Mocks are beans in that context |
| Q | What you ticked | What's actually true |
|---|---|---|
| Q10 | @Autowired(searchBy="type") | @Autowired has one attribute: required |
| Q33 | PlatformTransactionManagerAdvisor | No such class. It's TransactionInterceptor |
| Q45 | "System Registry Properties" | Spring reads JVM system properties and OS env vars, never the Windows registry |
| Q5 | server.timeout | No generic property. It's server-specific: server.tomcat.connection-timeout |
| Q47 | @ContextConfiguration for auto-config | Real, but it loads plain config classes. Auto-config needs @ImportAutoConfiguration |
| Q56 | @ComponentScan(excludeFilters) | Real, but auto-config classes are imported, not scanned |
#20 got the stopped-short count down to one. Today it's three, and they're the same kind of question: four options, three true, and you stopped at two. On a "select all" question, check each option on its own. Don't stop because two already feel like enough. Ruling an option out needs a reason, such as a name that doesn't exist or a job it doesn't do, so if you can't give one, tick it.
Thirteen misses is too many for one block, so they're split into three groups by what they test. Each group has its own drill.
| JDK dynamic proxy | CGLIB proxy | |
|---|---|---|
| What it is | A new class implementing the target's interfaces | A runtime subclass of the target class |
| Needs an interface? | Yes | No — that's why it exists |
| Final class | Fine (it never extends it) | Fails at startup |
| Final method | Fine (interface methods can't be final) | Silently not advised |
| Private / static method | Not advised | Not advised |
this.other() | Bypasses proxy | Bypasses proxy |
This is #13's question turned round. On #13 you gave JDK proxies CGLIB's "final"
limits. Today you gave CGLIB the JDK's "needs an interface" limit. Keep the two columns separate: JDK =
interfaces. CGLIB = subclass, so no final. Only self-invocation and private methods affect both.
final stops it. JDK implements interfaces, so it
needs one.| Mode | When | Who does it | Target's bytecode changed? |
|---|---|---|---|
| Compile-time (CTW) | Compiling | ajc | Yes |
| Post-compile | After compiling, on existing jars | ajc -inpath | Yes |
| Load-time (LTW) | As the classloader loads the class | Java agent + ClassFileTransformer | Yes, in memory only |
| Spring AOP | When the bean is created | A BPP wraps it in a proxy | No — not weaving |
The trap is that "load time" and "runtime" both happen while the app is running. The difference is what changes. LTW rewrites the class's bytes before the JVM defines it. A proxy is an extra object that sits in front of an unchanged target. No packaging step weaves anything either.
TransactionInterceptor ticked a false option same question as #15TransactionInterceptorPlatformTransactionManagerAdvisor. On #15 you ticked
TransactionStatusAdvice. Both are invented.The chain: @EnableTransactionManagement registers a
BeanFactoryTransactionAttributeSourceAdvisor. Its advice is a TransactionInterceptor.
When a proxied method is called, the interceptor reads the @Transactional attributes, asks the
PlatformTransactionManager for a transaction, calls the method, then commits or rolls back.
TransactionTemplate is the programmatic alternative. You call it yourself, and no proxy is
involved.
TransactionInterceptor (proxy). Programmatic =
TransactionTemplate (you).@Autowired, stereotypes, @Bean — Q10, Q28, Q32, Q34, Q50, Q60@Autowired ticked a false option invented attribute@Autowired has one attribute, and it works on fields, constructors and methods@Autowired(required=false, searchBy="type").
Q28: you ticked "injects by type, using setter methods only".| Fact | Detail |
|---|---|
| Attributes | Only required (default true). No searchBy, no name |
| Where | Constructor · field (private too) · setter or any method · parameter |
| How it resolves | By type → several matches? @Primary / @Qualifier / parameter name |
| Collections | List<T>, Set<T>, T[], Map<String,T> get every bean of type T |
| Private field | Works through reflection |
| Single constructor | @Autowired is optional (since 4.3) |
@Autowired: one attribute (required), by type, anywhere a
value can go in.@Configuration is a stereotype, because it's meta-annotated with @Component@Configuration. The answer was @Autowired.A stereotype marks a class as a component, so scanning picks it up. The test is simple: open
the annotation's source and look for @Component on it. @Service,
@Repository, @Controller, @RestController (through
@Controller) and @Configuration all have it. @Autowired goes on a field,
constructor or method, and it asks for a bean rather than declaring one.
@Autowired = "give me a
bean" on a member.BeanCurrentlyInCreationException regardless of
injection type".| Cycle | Plain Spring | Boot 2.6+ |
|---|---|---|
| Singletons, setter / field | Resolved: early reference | Fails unless spring.main.allow-circular-references=true |
| Singletons, constructor | BeanCurrentlyInCreationException | Same |
| Prototypes | BeanCurrentlyInCreationException | Same |
How it works: A is instantiated (constructor done, fields empty), and a factory for an "early
reference" to A goes into the singletonFactories cache. A asks for B. B is created and asks for A,
and gets the early reference. B finishes, then A finishes. A constructor cycle can't do this, because no
instance of A exists until its constructor returns, and that constructor is waiting for B. "Always throws" is
false, because of the setter case.
Field injection is the shortest form, so readability is the one thing in its favour. The real
objections: it breaks encapsulation (the container writes private state by reflection), it hides
dependencies (they aren't in the constructor), it stops fields being final, and it makes
the class harder to test (you need reflection or a Spring context to set the field).
@Bean can set stopped short@Bean can set the name, the init method and the destroy methodThree of four were true. @Bean's attributes are name/value,
initMethod, destroyMethod (default "(inferred)", which calls a public
close() or shutdown()) and autowireCandidate. The false option was
"include the class in component scanning". @Bean registers one object from a factory method and
has nothing to do with scanning.
@Bean(name, initMethod, destroyMethod, autowireCandidate).@PostConstruct / @PreDestroy constraints ticked a false option 3rd time: #7, #18, #21| Rule | Requirement | Why |
|---|---|---|
| Return type | void | Nobody reads a return value |
| Parameters | None | The container has nothing to pass |
| Static | Not allowed | It's called on the instance |
| Visibility | Any — private is fine | Called by reflection (setAccessible(true)) |
Link it to something you already get right: @Autowired works on a private field
because Spring uses reflection. @PostConstruct is called by a BPP (CommonAnnotationBeanPostProcessor)
the same way, so private works there too. "Public is recommended" isn't the same as "public is required".
private. If @Autowired can reach a
private field, a BPP can call a private @PostConstruct.| Step | What happens | Hook |
|---|---|---|
| 0 | Bean definitions loaded and edited | BeanFactoryPostProcessor |
| 1 | Instantiate (constructor) | — |
| 2 | Dependency injection | — |
| 3 | postProcessBeforeInitialization | BPP (@PostConstruct runs here) |
| 4 | afterPropertiesSet() → initMethod | — |
| 5 | postProcessAfterInitialization | BPP (AOP proxies made here) |
"Before instantiation" is a BFPP's territory: it works on definitions, when no instance
exists. A BPP receives Object bean as its argument, so the instance must already exist. #14 and #19
asked "when is it called?" (twice per bean). Today asked "when can it modify the instance?" The table above
answers both.
postProcessBeanFactory(), not postProcess()BFPP's whole job is transforming bean definitions, as in the table above (step 0). The incorrect
statement was "Its only method is named postProcess()". It does have only one method, but
it's called postProcessBeanFactory(ConfigurableListableBeanFactory). Spring's built-in ones are
PropertySourcesPlaceholderConfigurer (resolves ${…}) and
PropertyOverrideConfigurer.
On a "which is incorrect" question, check every option before you pick one. A statement with a slightly wrong name in it is the usual answer.
postProcessBeanFactory. BPP: two,
postProcessBefore/AfterInitialization.Environment in a web app ticked a false option invented source| Property source (highest first) | Non-web (StandardEnvironment) | Web (StandardServletEnvironment) |
|---|---|---|
servletConfigInitParams | — | ✓ |
servletContextInitParams | — | ✓ |
jndiProperties | — | ✓ |
systemProperties (JVM -D) | ✓ | ✓ |
systemEnvironment (OS env vars) | ✓ | ✓ |
| Profiles | ✓ | ✓ |
On #14 you gave the three web sources to a non-web app. Today's question was the web version, so
those three were right. "System" in Spring always means the JVM's System.getProperties() /
System.getenv(), never an OS registry.
spring-boot-starter-tomcat, add
spring-boot-starter-jetty" to get an external server (as on #8) and server.timeout.| Goal | How |
|---|---|
| Change port / context path / SSL | server.port, server.servlet.context-path, server.ssl.* |
| Anything programmatic | A WebServerFactoryCustomizer<T> bean |
| Timeout | Server-specific: server.tomcat.connection-timeout, server.jetty.connection-idle-timeout |
| Different embedded server | Exclude spring-boot-starter-tomcat, add …-jetty or …-undertow |
| External server | Package as WAR, extend SpringBootServletInitializer, Tomcat starter provided |
@ComponentScan(excludeFilters = …).
You got the three real switches.@EnableAutoConfiguration uses AutoConfigurationImportSelector, which reads
candidates from spring.factories (or AutoConfiguration.imports in 2.7+). It removes only
what exclude, excludeName and spring.autoconfigure.exclude list. Component
scanning never sees these classes. @SpringBootApplication even adds
AutoConfigurationExcludeFilter to make sure of that.
exclude (class), excludeName (string),
spring.autoconfigure.exclude (property). Scanning isn't one.@MockBean stopped short same as #11 Q11No false tick, so you left one of the three true options out, as on #11. The one most likely to
look wrong is "used to define a new Spring bean in the test context". It's true: if the context has no
bean of that type, @MockBean registers one. If it has one, the mock replaces it. The only false
option was "same as @Mock". @Mock is plain Mockito and never touches a Spring
context.
For later: Boot 3.4 deprecates
@MockBean in favour of Spring Framework's @MockitoBean. The exam is on Boot 2.x, so
answer with @MockBean.
@MockBean = replace or add, in the context.
@Mock = no context.@ImportAutoConfiguration@ContextConfiguration.| Annotation | Loads | Knows about auto-config? |
|---|---|---|
@ContextConfiguration | Plain @Configuration classes or XML (spring-test) | No |
@Import | A regular config / component class | No — skips its ordering |
@ImportAutoConfiguration | Named auto-config classes, with their conditions and ordering | Yes |
@SpringBootTest | The whole app | Loads all of it; you can't add one selectively |
@ImportAutoConfiguration(Xxx.class).33% is two misses out of three questions. It looks bad, but there's much less to fix than in Core.
The six constraints: client-server, stateless, cacheable, uniform interface, layered system, code on demand (optional). Scalability counts because it follows directly from statelessness: any server can handle any request. Resilience is about how the system is run (retries, failover), not one of REST's constraints. Related from #9: REST is an architectural style, not a protocol, and it is interoperable.
@RequestMapping doesn'tNo false tick, so you left one of @RequestParam, @PathVariable and
@RequestBody out. All three bind something from the request to a parameter. Others that go on a
parameter: @RequestHeader, @CookieValue, @ModelAttribute,
@MatrixVariable, @RequestPart. @RequestMapping goes on a class or method,
never on a parameter.
@RequestMapping maps the method. Every other
@Request… / @PathVariable fills a parameter.@PostConstruct: void, no params, not static, any visibility. Reflection ignores private. Third missfinal stops it. JDK implements interfaces → needs one. Self-invocation beats bothTransactionInterceptor. Programmatic = TransactionTemplate. No "Advisor"/"Advice" class@Autowired: one attribute (required), by type, field/constructor/any method, private OK@Component, @Configuration included. @Autowired isn't one@Bean(name, initMethod, destroyMethod, autowireCandidate). Scanning isn't its jobpostProcessBeanFactory. BPP: instances, around initEnvironment adds servlet config + servlet context + JNDI. No registry, everSpringBootServletInitializer. Timeouts are server-specificexclude, excludeName, spring.autoconfigure.exclude. Not scan filters@MockBean replaces or adds, in the context. @Mock has no context@ImportAutoConfiguration@RequestMapping maps methods. @RequestParam/@PathVariable/@RequestBody fill parametersTen questions with no topic label to prime you. For each option, name the class, method or property that would do it, and check it does this job. If you can't, it's false.
@PostConstruct
constraints (three times), LTW, the embedded server, TransactionInterceptor and
@MockBean.