Spring Bean Lifecycle practice questions

From Spring Certified Professional (Develop) (2V0-72.22) · 25 questions on this topic

Spring Bean Lifecycle practice questions from Spring Certified Professional (Develop) (2V0-72.22). This pack has 25 questions tagged Spring Bean Lifecycle, drawn from its timed mock exams. 8 of them are worked through in full below — the question, every option, why each is right or wrong, and the explanation.

Worked examples for Spring Bean Lifecycle

  1. Question 1

    An application that started successfully on Spring Boot 2.5 fails to start after upgrading to Spring Boot 2.7: two singleton beans depend on each other through setter (field) injection, and startup now reports an unsatisfied circular reference. Which TWO of the following are valid ways to make the application start again? Select TWO.

    1. A. Set `spring.main.allow-circular-references=true`, restoring the pre-2.6 behavior in which the container resolves the setter/field circular reference (Spring logs a warning recommending you refactor).Correct answer

      Correct. Spring Boot 2.6 prohibits circular references by default; this property re-enables the earlier resolution behavior for the whole application. It is the documented compatibility switch, and Spring still warns that the cycle should be refactored away.

    2. B. Annotate one of the two injection points with `@Lazy` so a lazy-resolving proxy is injected, meaning the two beans no longer need each other fully initialized at the same moment and the cycle is broken.Correct answer

      Correct. `@Lazy` on one side injects a proxy that resolves the target on first use, so neither bean requires the other to be fully constructed during its own creation. This breaks the cycle locally without allowing circular references globally.

    3. C. Mark the two beans `@Primary` so the container can choose between them and the circular reference is resolved.

      `@Primary` disambiguates among multiple candidate beans of the same type at an injection point; it has nothing to do with a circular dependency between two distinct beans and would not affect startup here.

    4. D. Switch both beans to constructor injection, since the 2.6 change only affects setter injection and constructor injection is unaffected.

      Reversed. Constructor-injection circular dependencies always fail with `BeanCurrentlyInCreationException`, and did so before 2.6. The 2.6 change is precisely that setter/field cycles, previously resolved, are now prohibited by default — moving to constructor injection makes this cycle fail harder, not start.

    5. E. Downgrade is the only option, because `spring.main.allow-circular-references` does not exist in Spring Boot 2.7.

      The property exists in Boot 2.6+ and is the intended switch for exactly this situation, so no downgrade is required.

    Explanation

    Spring Boot 2.6 changed the default so that circular references between beans are prohibited; an application that previously relied on Spring resolving a setter/field-injection cycle now fails at startup after upgrading. Two valid remedies exist: re-enable the legacy behavior globally with `spring.main.allow-circular-references=true` (Spring warns and recommends refactoring), or break the cycle locally by marking one injection point `@Lazy`, so a proxy is injected and the beans no longer require each other to be fully initialized simultaneously. Marking beans `@Primary` addresses candidate ambiguity rather than cycles; converting to constructor injection makes a cycle fail harder, because constructor cycles always throw `BeanCurrentlyInCreationException`; and the property does exist in 2.7, so no downgrade is needed.

  2. Question 2

    When does Spring create a CGLIB (subclass) proxy rather than a JDK dynamic proxy for a bean?

    1. A. When the target class implements no interface, or when proxyTargetClass=true is configuredCorrect answer

      Spring falls back to a CGLIB subclass proxy when the target implements no interface, and also whenever proxyTargetClass=true is set to force class-based proxying.

    2. B. Always — Spring only uses CGLIB

      Incorrect because it ignores JDK dynamic proxies: by default, when the target implements at least one interface, Spring uses a JDK dynamic proxy rather than CGLIB.

    3. C. Only for @Async methods, never for @Transactional

      The proxy mechanism is chosen from whether the target exposes interfaces and the proxyTargetClass setting, not from which annotation triggered the proxy, so tying it to specific annotations is wrong.

    4. D. Never — Spring only uses JDK dynamic proxies

      Incorrect because it denies CGLIB entirely: Spring does create CGLIB subclass proxies when there is no interface or when proxyTargetClass=true is configured.

    Explanation

    By default Spring creates a JDK dynamic proxy when the target implements at least one interface, and falls back to a CGLIB subclass proxy when the target implements none. Setting proxyTargetClass=true forces class-based CGLIB proxying regardless. Both proxy strategies exist, and the choice depends on interfaces and configuration rather than on which annotation caused the proxy.

  3. Question 3

    How does a bean obtain a reference to the ApplicationContext that created it?

    1. A. Construct a new ApplicationContext inside the bean

      Incorrect: constructing a new ApplicationContext creates a separate container rather than a reference to the one that made the bean.

    2. B. Implement ApplicationContextAware (or simply @Autowired the ApplicationContext)Correct answer

      Correct: implementing ApplicationContextAware (or simply autowiring the ApplicationContext) supplies the container to the bean.

    3. C. A bean cannot access its own container

      Incorrect: a bean can access its own container through the Aware callbacks or autowiring.

    4. D. Only a static global holder can provide it

      Incorrect: a static global holder is not the only way to obtain the container.

    Explanation

    The *Aware family of callback interfaces lets a bean receive framework objects; ApplicationContextAware supplies the container through setApplicationContext, and autowiring the ApplicationContext works as well. Constructing a fresh context would instead create a separate, unrelated container.

  4. Question 4

    A bean is declared with prototype scope, implements DisposableBean, and has a @PreDestroy method. When the ApplicationContext is closed, what does the container do with that bean's destruction callbacks?

    1. A. It calls @PreDestroy and DisposableBean.destroy() on every prototype instance it has handed out.

      The container does not track prototype instances after creation, so it has no registry of them to call destruction callbacks on at shutdown.

    2. B. It calls the destruction callbacks only on the most recently created prototype instance.

      The container keeps no reference to any prototype instance, most-recent or otherwise, so it does not invoke destruction callbacks on any of them.

    3. C. It does not call any destruction callbacks, because it does not track prototype instances after creation, so cleanup is the client's responsibility.Correct answer

      For prototypes the container runs initialization callbacks but then hands the bean off without tracking it, and therefore never invokes @PreDestroy or DisposableBean.destroy(); releasing resources is left to the client.

    4. D. Prototype-scoped beans cannot implement DisposableBean, so the context fails to start.

      A prototype may implement DisposableBean; the interface is simply ignored for prototypes at shutdown rather than causing a startup failure.

    Explanation

    For prototype-scoped beans the container instantiates and runs the initialization callbacks but then hands the instance off without retaining a reference. Because it does not track prototype instances, it never calls their destruction callbacks such as @PreDestroy or DisposableBean.destroy(); the client is responsible for cleanup. This contrasts with singletons, whose full destroy lifecycle the container manages at shutdown.

  5. Question 5

    A singleton bean has a @PreDestroy method, implements DisposableBean, and configures a custom destroy-method. When the context shuts down, in what order do these three destruction callbacks run?

    1. A. custom destroy-method, then DisposableBean.destroy(), then @PreDestroy

      This reverses the destruction order; the JSR-250 @PreDestroy callback runs first, not last, and the custom destroy-method runs last, not first.

    2. B. DisposableBean.destroy(), then @PreDestroy, then custom destroy-method

      @PreDestroy precedes DisposableBean.destroy(), so putting destroy() first is wrong even though the custom destroy-method does come last.

    3. C. @PreDestroy, then DisposableBean.destroy(), then custom destroy-methodCorrect answer

      On shutdown the container runs the JSR-250 @PreDestroy callback first, then DisposableBean.destroy(), then any custom destroy-method, mirroring the initialization order.

    4. D. All three run simultaneously; the container defines no order among them.

      The destruction callbacks run in a defined sequence, not simultaneously; @PreDestroy, then destroy(), then the custom destroy-method.

    Explanation

    At shutdown a singleton's destruction callbacks run in a fixed sequence: the JSR-250 @PreDestroy method first, then InitializingBean's counterpart DisposableBean.destroy(), then any custom destroy-method configured via @Bean(destroyMethod=...). This mirrors the initialization order, where @PostConstruct runs before afterPropertiesSet() before the custom init-method.

  6. Question 6

    Which TWO statements about marking one of several candidate beans @Primary are correct? Select TWO.

    1. A. An explicit @Qualifier at the injection point still takes precedence over a @Primary beanCorrect answer

      @Primary is only a default preference: when the injection point names a specific candidate with @Qualifier, that qualifier wins over the @Primary designation.

    2. B. It becomes the default choice when autowiring by type would otherwise be ambiguousCorrect answer

      @Primary designates the preferred candidate that Spring selects when a by-type injection would otherwise be ambiguous and no qualifier disambiguates it.

    3. C. It makes that bean the only one allowed of its type

      @Primary only marks a preference among multiple candidates; it does not forbid other beans of the same type from existing.

    4. D. It forces that bean to be created before all others

      @Primary is about candidate selection during autowiring, not instantiation order, so it does not force the bean to be created before others.

    Explanation

    @Primary designates the preferred candidate that Spring picks when a by-type injection would otherwise be ambiguous, so it acts as the default choice among several beans of the same type. That preference is not absolute, though: an explicit @Qualifier at the injection point still wins over @Primary. @Primary neither forbids other beans of the same type from existing nor changes instantiation order — it only affects candidate selection.

  7. Question 7

    A developer marks a full @Configuration class final so it is immutable, and the application fails to start. Why does a full @Configuration class forbid being final?

    1. A. Because @Configuration classes are loaded reflectively, and reflection cannot access final classes.

      Reflection can access final classes without issue; the real constraint comes from CGLIB subclassing, not reflective loading.

    2. B. Because Spring creates a CGLIB subclass proxy of a full @Configuration class to enforce singleton semantics on inter-bean @Bean calls, and CGLIB cannot subclass a final class.Correct answer

      A full @Configuration class is enhanced by a CGLIB subclass proxy that intercepts @Bean method calls so repeated calls return the same singleton; CGLIB must subclass the class, which is impossible if it (or its @Bean methods) are final.

    3. C. Because a final class is not permitted to declare @Bean methods at all.

      Declaring @Bean methods is unrelated to finality; the restriction exists specifically because CGLIB must subclass and override the class to provide full-mode call interception.

    4. D. Because final classes are treated as lite-mode configurations, which Spring Boot prohibits.

      Finality does not reclassify a @Configuration class into lite mode, and lite mode is not prohibited; the startup failure is the CGLIB subclassing constraint of full mode.

    Explanation

    When a class carries @Configuration, Spring creates a CGLIB subclass proxy that intercepts every @Bean method call so a repeated call returns the same container-managed singleton rather than re-running the method body. Because CGLIB must subclass and override the class, a full @Configuration class must not be final, and neither may its @Bean methods. This is a property of full mode; lite-mode @Bean methods on a plain @Component are not enhanced and carry no such restriction.

  8. Question 8

    A team has several beans of the same interface type and must resolve by-type injection ambiguity. Which TWO statements accurately describe how `@Primary` and `@Qualifier` behave in Spring?

    1. A. @Primary marks one candidate as the default choice, used whenever multiple candidates match and the injection point expresses no other preferenceCorrect answer

      This is exactly @Primary's role: a coarse-grained, definition-side default applied when by-type autowiring finds several candidates (Spring Framework Reference — Using @Primary or @Fallback to Fine-tune Annotation-based Autowiring).

    2. B. @Qualifier at an injection point narrows the candidate set by a qualifier value, and takes precedence over a @Primary bean of the same typeCorrect answer

      Qualifiers are fine-grained, injection-point-side selection; an explicit qualifier match wins over the coarse-grained @Primary default (Spring Framework Reference — Fine-tuning Annotation-based Autowiring with Qualifiers).

    3. C. Declaring @Primary on two beans of the same type is allowed and makes Spring inject whichever of the two was defined first

      Misconception that @Primary degrades to definition order. Two primaries among the matching candidates simply restore ambiguity, and resolution fails rather than picking the earlier definition.

    4. D. @Qualifier can only be placed on a bean definition, never on the field, constructor parameter, or setter parameter that receives the injection

      Inverts where qualifiers apply. @Qualifier is designed to be used on both sides — on the candidate to give it a value, and on the injection point to request that value.

    Explanation

    Spring resolves by-type ambiguity through two complementary mechanisms. @Primary is declaration-side and coarse-grained: it designates one candidate as the default when several match and the injection point states no preference. @Qualifier is injection-point-side and fine-grained: it names which candidate is wanted, and because it is an explicit request it overrides the default a primary bean would otherwise supply. Marking multiple matching candidates as primary does not create an ordering rule — it recreates the ambiguity and fails, and restricting qualifiers to bean definitions misstates their design, since their whole purpose is to be matched between a candidate and the point requesting it.

Practise all 25 Spring Bean Lifecycle questions

Spring Certified Professional (Develop) has the full set, inside timed mock exams that mirror real exam conditions — every question with a worked explanation.

Open Spring Certified Professional (Develop)

Other topics in this pack