Spring
The Spring framework — the IoC container, dependency injection, and bean scopes and lifecycle.
6 questions
JuniorTheoryVery commonWhat are the Spring IoC container and dependency injection?
What are the Spring IoC container and dependency injection?
Inversion of control means the framework, not your code, creates and wires objects. Spring's IoC container (the ApplicationContext) reads bean definitions, instantiates the beans, and supplies each bean's collaborators for it — that supplying is dependency injection, done via constructor, setter, or field. So a class declares what it needs and the container provides it, instead of the class calling new on its dependencies.
Common mistakes
- ✗Confusing inversion of control with reversing method call order
- ✗Thinking dependency injection copies beans rather than wiring shared references
- ✗Believing the container is compile-time only with no runtime role
Follow-up questions
- →What are the trade-offs of constructor injection versus field injection?
- →How does the container resolve which bean to inject when several match a type?
JuniorTheoryCommonWhat do the @Component, @Service, @Repository, and @Controller stereotypes do?
What do the @Component, @Service, @Repository, and @Controller stereotypes do?
All four mark a class as a Spring-managed bean that component scanning finds and registers in the container; @Component is the generic form and the other three are specializations of it. @Service is a plain semantic marker for business logic, @Repository additionally translates persistence exceptions into Spring's DataAccessException hierarchy, and @Controller marks a web handler that request mappings route to.
Common mistakes
- ✗Thinking
@Repositoryand@Servicediffer only in name, with no added behaviour - ✗Expecting a stereotype to decide the bean's scope
- ✗Forgetting that a class outside the scanned packages is never registered, however it is annotated
Follow-up questions
- →What extra behaviour does
@Repositoryadd that@Servicedoes not? - →Why is an annotated class outside the scanned base packages never registered as a bean?
MiddleTheoryCommonWhat is Spring AOP, and how does it apply a cross-cutting concern like logging?
What is Spring AOP, and how does it apply a cross-cutting concern like logging?
Aspect-oriented programming factors a cross-cutting concern — logging, metrics, security, transactions — out of the business code into an aspect: an advice (the code to run) plus a pointcut (where it runs). Spring AOP is proxy-based: at startup the container wraps the target bean in a JDK dynamic proxy or a CGLIB subclass, and the advice fires on calls that arrive through that proxy. So it intercepts only external calls on Spring beans, at method granularity.
Common mistakes
- ✗Thinking Spring AOP weaves bytecode instead of wrapping the bean in a proxy
- ✗Expecting an aspect to fire on a call the bean makes to its own method
- ✗Believing an aspect can advise an object created with
newoutside the container
Follow-up questions
- →When does Spring pick a CGLIB subclass proxy over a JDK dynamic proxy?
- →Why does an aspect never fire on a
privatemethod of the advised bean?
MiddleTheoryCommonWhat are Spring bean scopes, and are singletons thread-safe?
What are Spring bean scopes, and are singletons thread-safe?
A scope controls how many instances the container creates and how long they live: singleton (default) is one shared instance per container; prototype is a new instance per injection or lookup; request and session are one per HTTP request or session. The default singleton is NOT thread-safe by itself — the scope only manages instance count. If a singleton holds mutable state, concurrent requests can corrupt it; keep singletons stateless.
Common mistakes
- ✗Assuming the container makes singleton beans thread-safe automatically
- ✗Thinking the default scope is
prototyperather thansingleton - ✗Believing N requests to an endpoint create N singleton instances
Follow-up questions
- →How many bean instances handle ten concurrent requests to a singleton-scoped controller?
- →When does injecting a
prototypebean into a singleton fail to give you a new instance?
MiddleDesignCommonIn a design review a teammate defends @Autowired on private fields: it is shorter, a new collaborator can be added without touching a constructor, and it already works in production. The class under review is a @Service with seven injected collaborators, two of them used by a single rarely-called method. Its unit test needs a full Spring context to run at all, and last week's incident came from a collaborator still being null when a field initializer ran. You want the team to switch to constructor injection. Make the case: what does constructor injection guarantee that field injection cannot, what does it cost you, and when is setter or field injection still the reasonable choice?
In a design review a teammate defends @Autowired on private fields: it is shorter, a new collaborator can be added without touching a constructor, and it already works in production. The class under review is a @Service with seven injected collaborators, two of them used by a single rarely-called method. Its unit test needs a full Spring context to run at all, and last week's incident came from a collaborator still being null when a field initializer ran. You want the team to switch to constructor injection. Make the case: what does constructor injection guarantee that field injection cannot, what does it cost you, and when is setter or field injection still the reasonable choice?
Constructor injection makes every dependency explicit and mandatory: the object cannot exist half-wired, its fields can be final, and the class is testable with a plain new — no Spring context. It also surfaces design smells: seven collaborators sting because the constructor makes the god-class visible. The cost is verbosity, and a circular dependency now fails at startup instead of hiding. Setter injection stays reasonable for genuinely optional collaborators.
Common mistakes
- ✗Believing field and constructor injection are equivalent once the context is up
- ✗Thinking constructor injection resolves a circular dependency rather than exposing it
- ✗Keeping a Spring context in unit tests because the class cannot be built with
new
Follow-up questions
- →How does constructor injection turn a circular dependency into a startup failure?
- →When does
@Autowiredon a setter still beat constructor injection?
MiddleDebuggingOccasionalFix the import whose per-chunk @Transactional never rolls back
Fix the import whose per-chunk @Transactional never rolls back
@Transactional is applied by a proxy that wraps the bean, so it only takes effect on a call that enters the bean from outside. this.importChunk(chunk) is an in-object call that never leaves ImportService, bypasses the proxy, and starts no transaction at all — each save simply autocommits. Fix it by routing the call through the proxy: inject the bean into itself, move importChunk into a separate bean, or open the transaction explicitly with a TransactionTemplate.
Common mistakes
- ✗Expecting
@Transactionalto apply to a method the bean calls on itself - ✗Blaming the rollback rules when no transaction was ever started
- ✗Assuming
REQUIRES_NEWalone fixes a call that never reaches the proxy
Follow-up questions
- →Why does making
importChunkprivateorfinalbreak@Transactionalin the same way? - →What are the risks of self-injecting a bean to send a call back through its own proxy?