A bean is simply an object whose lifecycle is managed by the Spring container — instantiated, configured, dependency-injected, and assembled by the ApplicationContext from a bean definition. The word sounds grander than it is: a bean is a plain Java object plus the metadata that tells Spring how to build and manage it.
Bean definition vs. bean instance
Keep two things distinct. A bean definition is the recipe — the metadata Spring reads (the class, scope, constructor args, properties, init/destroy callbacks, lazy flag). It comes from a @Bean method, a component-scanned @Component, or XML. The bean is the actual instance the container produces from that recipe. One definition can yield one instance (singleton) or many (prototype).
What the container does with it
For each definition the container runs a defined lifecycle:
- Instantiate — call the constructor (or factory
@Beanmethod). - Populate / inject — resolve and set dependencies (
@Autowired, constructor args). - Aware callbacks —
BeanNameAware,ApplicationContextAware, etc. BeanPostProcessor.postProcessBeforeInitialization— this is where AOP proxies,@Transactional, etc. get applied.- Initialization —
@PostConstruct, thenInitializingBean.afterPropertiesSet(), then a custominitMethod. postProcessAfterInitialization— the bean is now ready and registered.- In use for the life of the context.
- Destruction —
@PreDestroy/DisposableBean.destroy()/destroyMethodon context shutdown (singletons only).
@Component
public class CacheWarmer {
@PostConstruct
void init() { /* runs after injection, before the bean is handed out */ }
@PreDestroy
void cleanup(){ /* runs on context shutdown */ }
}
Scope — how many instances
The default scope is singleton: one shared instance per ApplicationContext (not a JVM-wide GoF singleton — two contexts have two instances). Other scopes: prototype (a fresh instance every injection/lookup; the container does not manage its full lifecycle or call destroy callbacks), and web scopes request, session, application, websocket.
@Bean
@Scope("prototype")
PdfReport report() { return new PdfReport(); }
A subtle trap: injecting a prototype bean into a singleton gives you exactly one prototype instance, captured once at wiring time — to get a fresh one per call you need ObjectProvider, a lookup method, or scoped-proxy.