On revision 2 you scored 43/62 (69%). The number that matters went up: on new questions you got 23/37 (62%), up from 15/34 (44%). This page goes through the 19 you missed, using exactly what you picked.
BeanCurrentlyInCreationException for A(B b)
/ B(A a), and "constructor injection exposes cycles". That was the main wrong belief on revision 2.Environment: plain main() = the two system sources, "servlet" = web only,
and HOME is readable in a web app. All right.server.tomcat.connection-timeout picked twice, after missing it
on every earlier try.1. Leaving out true options. In 10 of the 19, you left out an option that was true. In six of them you ticked nothing false, so the only mistake was stopping too soon:
| Question | True option you left out |
|---|---|
Where can @Lazy go? | On a @Component class |
| Which bring in auto-config? | @ImportAutoConfiguration, which you picked correctly in two other questions |
@MockBean (block C) | Replaces an existing bean · separate cached contexts |
@MockBean (retry) | Field or class · adds one if none exists |
| Real Boot 2.5 properties | server.port |
| Boot 2.7 cycle fixes | @Lazy |
The fix is a technique, not more facts. On "select all", treat each option as a separate true/false question, and give each a yes or no before you click Check. The true-or-false block trains exactly that.
2. An old wrong answer coming back. In block A you correctly put
@Lazy on a field and a constructor parameter. Then the retry showed the revision-1 wording, and you
picked "nothing — @Lazy only works on classes", your revision-1 answer, again. Familiar
wording brings back the answer you gave last time, not the rule. When an option feels familiar, check it
against the rule anyway.
Each finished block is recorded in this browser. Reload to retake. Order: blocks 1–6, then true or false, then the retry. On every "select all", give each option a yes or no before you click Check.
| Drill block | Qs | Last | Best | Runs | Last done |
|---|---|---|---|---|---|
| Loading… | |||||
@Lazy and which cycles start — 6 misses
2 · @MockBean and the auto-config annotations — 5 misses
3 · exclude vs excludeName, scan filters — 3 misses
4 · Which proxy problems are silent — 2 misses
5 · Web Environment adds, it doesn't replace — 2 misses
6 · What a BPP receives — 1 miss
True or false: the options you keep ticking
Retry the 19, exact wording
@Lazy, and which cycles start 6 misses@Lazy and field cycles in plain Spring are left| Question | You picked | Right answer |
|---|---|---|
Where can @Lazy go? | parameter + field (left out class) | class + field + parameter |
@Lazy on a constructor parameter? (retry) | "nothing — only works on classes" — same as revision 1 | injects a lazy proxy |
| Boot 2.7 field-cycle fixes (retry) | refactor + property (left out @Lazy) | refactor + property + @Lazy |
| Plain-Spring constructor cycle fixes | setter + refactor + the Boot property (left out @Lazy) | setter + refactor + @Lazy |
| Plain Spring, field-injection cycle | BeanCurrentlyInCreationException | starts |
| Which throw, plain Spring? (retry) | constructor + field (left out prototypes) | constructor + prototypes |
@Lazy is in four of these, so learn it as one picture. It has two
jobs, depending on where you put it:
@Lazy @Component class ReportService { … } // on a CLASS (or @Bean method):
// the bean itself is created on first use
class A {
A(@Lazy B b) { … } // on an INJECTION POINT (parameter, field):
@Autowired @Lazy C c; // Spring injects a proxy now and looks up
} // the real B / C on first call
The injection-point form is what breaks cycles. A gets a stand-in for B straight away, so A's
constructor finishes without waiting for B. That works for any cycle, constructor ones included, in
plain Spring and in Boot. It's the one fix that's always on the list. Compare the property:
spring.main.allow-circular-references=true is Boot-only, and it only brings back the
setter/field behaviour. It never rescues a constructor cycle.
The field-cycle misses: read "plain Spring" vs "Boot". In plain Spring, field injection behaves like setter injection, since both happen after the constructor. So a field cycle between singletons starts. It fails only in Boot 2.6+ (the default) and for prototypes. Before answering, underline which one the question says:
| Plain Spring | Boot 2.6+ default | Fixed by @Lazy? | Fixed by the property? | |
|---|---|---|---|---|
| Field / setter, singletons | Starts | Fails | Yes | Yes (Boot) |
| Constructor, singletons | Fails | Fails | Yes | No |
| Prototypes | Fails | Fails | Yes | No |
@Lazy goes anywhere (class, field, parameter) and
always breaks a cycle. The property is Boot-only and setter/field-only. Plain Spring: field = setter = starts."@MockBean, and the annotations that bring in auto-config 5 misses@MockBean has three true facts. You keep picking one or two| Question | You picked | Right answer |
|---|---|---|
@MockBean: which are true? (block C) | only "adds a bean if none exists" | + replaces existing · + separate cached contexts |
@MockBean: which are true? (retry) | only "registers a mock in the context" | + field or class · + adds one if none |
@DataJpaTest needs Acme's auto-config (retry) | @MockBean AcmeClientAutoConfiguration | @ImportAutoConfiguration(…) |
| Which bring in auto-config? | Enable + SpringBootApplication (left out Import) | all three |
@ContextConfiguration(classes = AppConfig.class) is closest to… | @ImportAutoConfiguration(AppConfig.class) | new AnnotationConfigApplicationContext(AppConfig.class) |
@MockBean as one picture. Every true statement about it comes from
this:
@WebMvcTest(OrderController.class)
@MockBean(AuditLog.class) // ① on the CLASS: a mock goes in the context, no field
class OrderControllerTest {
@MockBean PaymentClient payments; // ① on a FIELD: a mock goes in the context AND into this field
}
// ② what happens to the context, for each @MockBean type:
// a PaymentClient bean already exists → the mock REPLACES it
// no PaymentClient bean exists → the mock is ADDED
// ③ the set of mocks is part of the context's cache key:
// test classes with different @MockBean sets get separate contexts (slower suite)
If you can answer ① where it goes, ② replace and add, and ③ caching, you can't
under-select. The only false one is "same as @Mock": @Mock never touches a Spring
context.
Why @MockBean can't bring in auto-config: it would register a
Mockito mock of the auto-config class. A mock is an empty stand-in, and Spring never reads its
@Bean methods, so none of the beans Acme should provide would be created.
The annotations that bring in auto-config. All three have "AutoConfiguration" in the name, or contain an annotation that does:
| Annotation | Brings in |
|---|---|
@EnableAutoConfiguration | every auto-config whose conditions match |
@SpringBootApplication | the same, because it includes @EnableAutoConfiguration |
@ImportAutoConfiguration(X.class) | only the ones you name. Slice tests use it internally |
@ContextConfiguration, @Import, @MockBean | no auto-config |
"Closest to" @ContextConfiguration: both it and
@ImportAutoConfiguration take classes, which is why they look alike. Ask what happens to the class
you pass. @ContextConfiguration builds the test context from your classes, as plain config,
just like new AnnotationConfigApplicationContext(AppConfig.class). In a Boot test it also
replaces the usual search for your @SpringBootApplication, which is why it's wrong for adding
one extra thing.
@MockBean: field or class; replace or add; cached
separately. Auto-config only enters through a name with AutoConfiguration in it."exclude vs excludeName, and scan filters 3 misses · the scan filter for the 3rd time| Question | You picked | Right answer |
|---|---|---|
| Which can remove an auto-config class? (no mention of a missing class) | property + excludeName + @ComponentScan filter (left out exclude) | exclude + excludeName + property |
Why does exclude = Foo.class fail when Foo's jar is missing? | "it works — exclude and excludeName are the same" | the class literal doesn't compile |
| Real Boot 2.5 properties | the two timeouts (left out server.port) | server.port + both timeouts |
Look at the two attributes' Java types:
public @interface SpringBootApplication {
Class<?>[] exclude() default {}; // exclude = Foo.class ← needs Foo to compile
String[] excludeName() default {}; // excludeName = "com.acme.Foo" ← never needs Foo
}
They have the same effect when Foo is on the classpath. They're not the same when it
isn't, because a .class literal is checked by the compiler. So "can it remove an auto-config?" gives
exclude a yes, and "the jar is missing" gives it a no. Check which question you're answering.
@ComponentScan(excludeFilters) is wrong every time. This is the
third time you've ticked it (exam Q56, revision 1, today). Scanning never finds auto-config classes in the first
place. They're imported from a list (spring.factories) by
AutoConfigurationImportSelector, so a scan filter has nothing to filter.
server.port: the timeout options made it feel like a timeout
question, but the question was "which are real?". server.port is the best-known Boot property there
is. Giving each option its own yes or no would have caught it.
| Question | You picked | Right answer |
|---|---|---|
| Which start fine, but the advice silently doesn't run? | self-invocation + final class (left out private + final method) | self-invocation + private + final method |
CGLIB-proxied class, public final void issue() | "startup fails" | runs without a transaction |
You got "final class → startup fails" right in both retries, then applied it to the final method as well. There's only one loud case, so learn that one and treat everything else as silent:
| Is there a proxy? | What you see | |
|---|---|---|
| Final class, no interface | No — none can be built | LOUD: startup fails (AopConfigException) |
| Final method | Yes | Silent: the subclass can't override it, so the call passes straight through |
| Private method | Yes | Silent: can't be overridden |
this.method() | Yes | Silent: the call never goes through the proxy |
The test is "is there a proxy?" If there is one, the app starts, and certain calls just slip past it. Startup only fails when Spring can't build a proxy at all.
Environment adds sources; it doesn't replace them 2 misses| Question | You picked | Right answer |
|---|---|---|
| Web vs non-web environment | "three different sources instead of the system ones" | the same two, plus three more |
A <context-param> from web.xml — which can see it? | "both" | StandardServletEnvironment only |
It's Java inheritance. This is a simplified version of the Spring 5 source:
public class StandardServletEnvironment extends StandardEnvironment { // ← EXTENDS
protected void customizePropertySources(MutablePropertySources sources) {
sources.addLast(servletConfigInitParams);
sources.addLast(servletContextInitParams);
if (jndiAvailable) sources.addLast(jndiProperties);
super.customizePropertySources(sources); // ← then adds systemProperties + systemEnvironment
}
}
The web class is a subclass, and it calls super, so it keeps everything the
non-web one has. "Instead of" would mean losing env vars in a web app, and you already knew
env.getProperty("HOME") works there.
<context-param>: the servlet container reads web.xml
and exposes the values through the ServletContext. A non-web app has no web.xml and no
ServletContext object at all, so there's nowhere for the value to come from. That makes it
"servlet" → web only, the same rule you applied correctly to the property-source names.
web.xml needs a ServletContext, so web only."postProcessBeforeInitialization gets the object, not the definitionRead the method name: Initialization. Only an object gets initialised, through
@PostConstruct and init methods. A definition is never initialised. The signature is
postProcessBeforeInitialization(Object bean, String beanName). Definitions are the BFPP's job, and
it gets the whole factory.
Each of these is an option you've ticked, or left out, at least once across the paper and the three revision pages. Answering one statement at a time trains the habit that fixes under-selection: every option gets its own yes or no.
The 19 questions you missed on revision 2, reshuffled. Do this last. On each "select all", give every option a yes or no before you click Check, and if an option feels familiar, check it against the rule anyway.