Overview
This page covers how Spring creates and wires your objects — the heart of the framework. After this you should be able to explain what a bean is, how it gets created, how dependencies are injected, and the traps interviewers love.
Official: IoC Container.
Table of contents
- Bean = object managed by Spring
- How Spring finds beans
- Stereotypes
@Componentvs@Bean- Injection: constructor, setter, field
- Bean scopes
@Primaryand@Qualifier- Lifecycle:
@PostConstruct/@PreDestroy - Circular dependencies
- Interview questions
- Summary
1. Bean = object managed by Spring
In plain Java you new everything. In Spring you tell the container “create one OrderRepository and one OrderService, and give the repository to the service”. The resulting objects are beans.
Default scope is singleton — one shared instance per container. That’s safe as long as the bean is stateless (no per-user mutable fields).
2. How Spring finds beans
When you put @SpringBootApplication on com.example.demo.DemoApplication, Spring scans:
com.example.demoand all sub-packages
for classes annotated with @Component (or any stereotype that includes @Component).
Common mistake: a service in com.example.orders while main is in com.example.demo → Spring never sees it. Move the class under the scan root, or add @ComponentScan("com.example.orders").
3. Stereotypes
All of these mean “this class is a bean” — they’re variants of @Component.
| Annotation | Used for | Extra |
|---|---|---|
@Component |
Generic bean | — |
@Service |
Business logic | Just a label |
@Repository |
DB access | Adds exception translation (SQL → DataAccessException) |
@Controller |
Web MVC returning views | Used with templates |
@RestController |
REST APIs | @Controller + @ResponseBody (returns JSON) |
4. @Component vs @Bean
@Component |
@Bean |
|
|---|---|---|
| Where | On a class | On a method inside @Configuration |
| Who creates the instance | Spring (calls constructor) | You (return new Thing()) |
| Use for | Your own classes | Third-party classes you can’t annotate |
@Configuration
public class AppConfig {
@Bean
Clock clock() { return Clock.systemUTC(); }
}
5. Injection: constructor, setter, field
Constructor injection — prefer this
@Service
public class OrderService {
private final OrderRepository orders;
public OrderService(OrderRepository orders) {
this.orders = orders;
}
}
- Dependencies are visible in the signature.
- Fields can be
final→ immutable, thread-safe references. - Tests can call
new OrderService(mockRepo)without Spring. - A class with a single constructor is autowired automatically — no
@Autowiredneeded.
Setter injection
For optional dependencies. Rare in modern code.
Field injection (@Autowired on a field)
Hides dependencies, prevents final, hard to test. Avoid.
6. Bean scopes
| Scope | Meaning | Use for |
|---|---|---|
| singleton (default) | One instance per context | Most services, repositories |
| prototype | New instance every time it’s asked for | Stateful builders |
| request / session | One per HTTP request / session | Rare in modern stateless APIs |
Classic trap — prototype in singleton:
You make ReportBuilder prototype, inject it into singleton ReportService. Spring builds the service once, so it gets one builder forever — not a fresh one per call.
Fix: inject ObjectProvider<ReportBuilder> or use a scoped proxy.
7. @Primary and @Qualifier
When two beans implement the same interface:
@Primaryon one bean — “prefer this one by default”.@Qualifier("emailSender")on the injection point — pick by name.
public AlertService(@Qualifier("smsSender") NotificationSender s) { ... }
Otherwise Spring fails at startup with NoUniqueBeanDefinitionException.
8. Lifecycle: @PostConstruct / @PreDestroy
@PostConstruct
void init() { /* runs once after injection */ }
@PreDestroy
void cleanup() { /* runs on shutdown */ }
For “app is fully ready” (not just one bean), listen for ApplicationReadyEvent instead.
9. Circular dependencies
A needs B, B needs A. With constructor injection, Spring can’t construct either → startup fails with BeanCurrentlyInCreationException.
Fixes:
- Refactor — extract a third class so the graph is a DAG. Best fix.
@Lazyon one constructor parameter — proxies the dependency, resolved on first use.ObjectProvider<X>— deferred lookup.
10. Interview questions
Q: What is Inversion of Control? A: The framework, not your code, creates and wires objects. DI is how Spring delivers IoC.
Q: What is a bean? A: An object Spring instantiates, configures, and manages. It has a name, a type, and a scope (default singleton).
Q: Why constructor injection?
A: Required dependencies are explicit, fields can be final, and tests can new the class without Spring.
Q: Default scope?
A: Singleton — one instance per ApplicationContext.
Q: Does singleton mean thread-safe? A: No. It means one instance. Thread safety is your job if the bean has mutable state. Stateless services are the norm.
Q: Two beans of the same type — what happens?
A: Spring throws NoUniqueBeanDefinitionException. Fix with @Primary or @Qualifier.
Q: Prototype injected into singleton — what’s the trap?
A: The singleton captures one prototype instance forever. Use ObjectProvider<T> to fetch a fresh one per call.
Q: Circular dependency — how do you fix it?
A: Refactor first. Tactically, @Lazy on one constructor parameter or ObjectProvider works.
Q: Can you new a @Service yourself?
A: Yes, but it won’t be a managed bean — no proxy, so @Transactional, @Async, etc. won’t work.
11. Summary
| Idea | One line |
|---|---|
| Bean | Object Spring creates and manages |
| DI | Dependencies passed in via constructor |
| Scan | Package of @SpringBootApplication + sub-packages |
| Scope | Singleton by default; watch the prototype-in-singleton trap |
| Lifecycle | @PostConstruct / @PreDestroy |
Next steps
- Auto-configuration & starters
- Pitfalls & proxies — self-invocation, CGLIB, why advice sometimes doesn’t fire
Happy Learning