Handbooks / Spring Boot / Chapter 2
Core: IoC and Dependency Injection
7 pages · ~5 min✓ Reviewed
Builds on Build Tools and Project Setup. Next up: Building REST APIs.
Spring Container and Bean Mental Model
1. Beans and Containers
- A bean is an object the IoC container creates, wires and manages
- IoC: the container builds objects and supplies dependencies, not your
new
| BeanFactory | ApplicationContext | |
|---|---|---|
| Beans | Lazy creation | Eager singletons at startup |
| Extras | Basic container | Events, i18n, property resolution |
| Use | Rarely | Use this in practice |
2. Startup and Scanning
- Read configannotations / Java config
- BeanDefinitionsbuilt
- Instantiate
- Injectdependencies
- Init callbacks
@SpringBootApplicationincludes@ComponentScan- It finds stereotype classes in its own package and sub-packages only
Silent skip
Classes outside the main class's package tree are skipped with no error.
3. Lookup and Interview Point
context.getBean(Type.class)fetches a bean by type- Prefer injection; getBean in business code is the service locator anti-pattern
- BeanFactory vs ApplicationContext? Lazy basics vs eager startup plus events, i18n, properties
- Why is my bean missing? It sits outside the scanned package tree
Stereotypes and Constructor Injection
1. Stereotype Annotations
| Annotation | Layer | Extra |
|---|---|---|
@Component | generic | base stereotype |
@Service | business logic | same registration |
@Repository | persistence | exception translation |
@Controller / @RestController | web | serves requests |
@Serviceand@Repositoryare specializations of@Component@RepositoryturnsSQLExceptioninto Spring's DataAccessException hierarchy
Bean Scopes and Lifecycle
1. Scopes
| Scope | Instances | Note |
|---|---|---|
singleton (default) | one per container | stateless or thread-safe |
prototype | new per injection or lookup | no destroy callbacks |
request session application | per request, session, app | web-only |
- Singleton is one per container, not per JVM
- Shared by all threads, so keep it stateless
2. Prototype inside a singleton
@Configuration and @Bean
1. What it does
- @Configuration marks a class holding
@Beanmethods - Return value becomes a bean, named after the method
- Class is CGLIB-proxied: repeated bean-method calls return the same singleton
| @Bean | Stereotype | |
|---|---|---|
| Use for | third-party classes | your own classes |
| Examples | ObjectMapper, RestTemplate, DataSource | @Service, @Repository |
2. Wiring and hooks
Auto-Configuration, Starters, Profiles and Properties
1. Starters and Auto-Config
- Starter = dependency bundle with managed versions, no logic
- Examples:
spring-boot-starter-web,-data-jpa,-test - Registered in
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - Conditions:
@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnProperty - Your bean of the same type overrides the default; debug with
--debug
- Starteron classpath
- Conditionmatches
- Default beancreated
- Your beanwins
2. Properties
| Priority |
|---|
Spring Core Cheat Sheet
1. Annotations and injection
| Annotation | Use |
|---|---|
@Component @Service @Repository @Controller | Register your own classes as beans |
@Configuration + @Bean | Third-party objects you cannot annotate |
@Primary | Default pick among candidates |
@Qualifier("name") | Pick one at the injection point |
- Constructor injection for required dependencies
- Fields are
final; one constructor needs no@Autowired - Setter injection only for optional ones
Check yourself
A singleton OrderService has a field @Autowired Cart cart, and Cart is a prototype bean. Do two requests get different carts?
- No: one Cart is injected once, at singleton creation.
- Fix: inject
ObjectProvider<Cart>and callgetObject()per use.
Two PaymentGateway beans exist and PayService(PaymentGateway g) is the only constructor. What happens at startup?
NoUniqueBeanDefinitionException: Spring cannot pick one.- Fix:
@Primaryon the default bean, or@Qualifier("name")on the parameter.
A @Component class has @Bean DataSource ds() and @Bean Repo repo() { return new Repo(ds()); }. Is the DataSource shared?
- No: lite mode has no proxy, so
ds()makes a new instance. - Fix: use
@Configuration, or takeDataSourceas a method parameter.