๐ฟ Beans Layer โ Anatomy, Annotations & Lifecycle Cheatsheet¶
Essence: Beans are the living objects Spring creates, wires, and manages inside the ApplicationContext. The Beans Layer covers what they are, how they live and die, and how their metadata is described through BeanDefinitions.
๐งญ 1. Concept Overview¶
A Spring bean is a normal Java object, but:
- Its lifecycle is controlled by the Spring container, not you.
- Itโs created via reflection, wired via dependency injection, and destroyed gracefully.
- Everything about it โ class, scope, dependencies, and init/destroy callbacks โ is stored in a BeanDefinition.
Think of each bean as a citizen of Springโs managed world โ born, connected, and retired by the container.
๐งฉ 2. Declaring Beans¶
You can register beans in three main ways:
๐งฑ Component Scanning (Annotation-based)¶
Spring scans packages for these stereotypes:
| Annotation | Role |
|---|---|
@Component |
Generic Spring-managed bean |
@Service |
Service-layer bean (semantic marker) |
@Repository |
Persistence-layer bean (adds exception translation) |
@Controller |
Web MVC component |
@Configuration |
Source of explicit bean definitions |
โ๏ธ Explicit Bean Registration (Configuration Class)¶
@Configuration
public class AppConfig {
@Bean
public AuditService auditService() {
return new AuditService();
}
}
Each @Bean method returns an object that Spring registers as a managed bean.
๐งฎ XML Configuration (Legacy)¶
Old style, still supported but rarely used in modern applications.
๐งฌ 3. BeanDefinition โ The Blueprint Metadata¶
When Spring detects a bean, it doesnโt create it immediately. It first builds a BeanDefinition โ a metadata record describing:
| Property | Meaning |
|---|---|
beanClass |
Actual Class<?> |
scope |
singleton, prototype, etc. |
autowireMode |
How dependencies are injected |
initMethodName |
Custom initialization method |
destroyMethodName |
Cleanup method |
lazyInit |
Whether bean is created on demand |
dependsOn |
Other beans that must be created first |
Example (simplified pseudocode):
BeanDefinition bd = new BeanDefinition();
bd.setBeanClass(PaymentService.class);
bd.setScope("singleton");
bd.setInitMethodName("init");
bd.setDestroyMethodName("cleanup");
This blueprint is what the BeanFactory later uses to actually create the instance.
โ๏ธ 4. Bean Scopes โ Controlling Lifespan¶
| Scope | Meaning | Created | Destroyed |
|---|---|---|---|
singleton |
One instance per container | On context start | On context close |
prototype |
New instance per request | On demand | Not tracked |
request |
One per HTTP request | On web request start | On web request end |
session |
One per HTTP session | On session start | On session end |
application |
One per ServletContext | On context init | On shutdown |
๐ง 5. Bean Lifecycle Stages¶
1. Definition created (BeanDefinition)
2. Instance constructed (reflection)
3. Dependencies injected (@Autowired, @Value)
4. Lifecycle callbacks triggered (@PostConstruct, init-method)
5. Bean enters ready state
6. On context shutdown โ @PreDestroy or destroy-method called
Lifecycle Annotations and Interfaces¶
| Type | Example | Purpose |
|---|---|---|
| Annotation | @PostConstruct |
After injection |
| Annotation | @PreDestroy |
Before destruction |
| Interface | InitializingBean.afterPropertiesSet() |
Post-injection initialization |
| Interface | DisposableBean.destroy() |
Cleanup |
| XML Attr | init-method / destroy-method |
Legacy equivalent |
Example¶
@Component
public class ConnectionPool {
@PostConstruct
public void init() { System.out.println("Pool ready"); }
@PreDestroy
public void shutdown() { System.out.println("Pool closed"); }
}
Output:
๐งฉ 6. Dependency Injection Timing¶
Spring always injects dependencies before calling any init methods.
Thatโs why you can safely rely on @Autowired fields or constructor-injected dependencies inside your @PostConstruct.
๐งฎ 7. Lazy and Conditional Beans¶
Lazy¶
Created only when first requested.
Conditional¶
@Bean
@ConditionalOnProperty("feature.x.enabled")
public FeatureX feature() { return new FeatureX(); }
Used heavily in Spring Boot auto-configuration.
๐งญ 8. Common Pitfalls¶
| Symptom | Cause | Fix |
|---|---|---|
BeanCurrentlyInCreationException |
Circular dependency | Break cycle or use @Lazy |
NullPointerException on injected field |
Bean not scanned | Fix @ComponentScan path |
NoSuchBeanDefinitionException |
No bean found | Annotate or register bean |
| Init/destroy not called | Wrong signature | Must be public void no-arg method |
| Prototype beans not destroyed | Expected behavior | Manage manually if needed |
โ๏ธ 9. Inspecting Beans at Runtime¶
@Autowired
ApplicationContext ctx;
public void debugBeans() {
for (String name : ctx.getBeanDefinitionNames()) {
System.out.println(name + " โ " + ctx.getType(name));
}
}
๐งฉ 10. Custom BeanPostProcessor¶
Advanced hook that modifies beans before/after initialization.
@Component
public class LoggerInjector implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) {
// before @PostConstruct
return bean;
}
public Object postProcessAfterInitialization(Object bean, String name) {
// after @PostConstruct
return bean;
}
}
Used internally for:
- Autowiring processor
- AOP proxy creation
- Validation, caching, and more
๐งญ 11. Quick Reference Summary¶
| Concept | API / Annotation | Purpose |
|---|---|---|
| Declare bean | @Component, @Service, @Bean |
Register with container |
| Describe bean | BeanDefinition |
Internal metadata |
| Define scope | @Scope("...") |
Control lifespan |
| Init phase | @PostConstruct / afterPropertiesSet() |
Setup |
| Destroy phase | @PreDestroy / destroy() |
Cleanup |
| Post-processing | BeanPostProcessor |
Modify beans |
| Lazy loading | @Lazy |
Create on demand |
| Conditional creation | @Conditional... |
Context-based activation |
๐งฉ 12. How BeanDefinition Links to Lifecycle¶
@Component โ Scanned by Reflection
โ
BeanDefinition โ Metadata stored
โ
BeanFactory โ Instantiates using reflection
โ
@Autowire / @Value โ Dependencies injected
โ
@PostConstruct โ Init logic
โ
Context Active
โ
@PreDestroy โ Cleanup
BeanDefinition is the blueprint; the Bean instance is the living object built from it.
๐ Related¶
- Concept: Bean Anatomy
- Concept: Context Lifecycle
- Cheatsheet: reflection-layer.md
- Cheatsheet: applicationcontext.md
๐ช Core Takeaway¶
Reflection lets Spring build objects. The Beans Layer teaches them how to live. Every bean in the container is born from a BeanDefinition, configured through annotations, and guided through a full lifecycle โ from reflective creation to graceful destruction.