What is a Bean in Spring
In the Spring Framework, a Bean is any Java object that is instantiated, assembled, configured, and managed throughout its entire lifecycle by the Spring Inversion of Control (I...
🟢 Junior Level
1. What is a Spring Bean?
In the Spring Framework, a Bean is any Java object that is instantiated, assembled, configured, and managed throughout its entire lifecycle by the Spring Inversion of Control (IoC) Container (represented by ApplicationContext).
In traditional Java programming, developers manage object instantiation and lifecycle manually:
// Regular Java Object (POJO): Developer manually controls instantiation via `new`
User user = new User("Alice");
In Spring, object creation and wiring are inverted and delegated to the framework:
// Spring Bean: Managed, instantiated, and wired by the IoC Container
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}
2. Regular Java Object (POJO) vs Spring Bean
A Spring Bean is technically a standard Java class, but the container enhances it with enterprise capabilities:
| Feature | Regular Java Object (POJO) | Spring Managed Bean |
|---|---|---|
| Creation | Explicitly by developer via new |
Automatically by Spring IoC Container |
| Dependency Resolution | Manual argument passing | Automatic Dependency Injection (@Autowired) |
| Lifecycle Hooks | Manual method calls | Automated callbacks (@PostConstruct, @PreDestroy) |
| Enterprise Aspects | None (pure plain code) | Enhanced via Dynamic Proxies (@Transactional, @Async) |
| Scope Management | Controlled by variable reference scope | Managed by container (singleton, prototype, request) |
🟡 Middle Level
1. The Blueprint: BeanDefinition
Before a bean physically exists in the JVM heap, Spring scans application configuration and constructs a metadata blueprint called BeanDefinition:
Configuration Source (@Component, @Bean, or XML)
│
▼
[BeanDefinition]
├── Target Class Name (`com.example.service.UserService`)
├── Scope (`singleton`, `prototype`, `request`, etc.)
├── Constructor Arguments & Injected Property Values
├── Primary & Qualifier Tags
├── Initialization & Destruction Method Names
└── Lazy Initialization Flag (`lazyInit = true/false`)
│
▼
[Instantiation Phase] ──► Real Bean Instance in Heap
BeanDefinition acts as a manufacturing specification. The BeanFactory reads this specification to instantiate and wire the physical bean. Developers can inspect or alter these specifications prior to instantiation by implementing BeanFactoryPostProcessor (e.g., PropertySourcesPlaceholderConfigurer which resolves ${...} property placeholders).
2. The 3 Primary Ways to Declare Beans
- Stereotype Annotations (Classpath Scanning):
@Component: Generic foundational stereotype.@Service: Business logic and transaction orchestration layer.@Repository: Persistence layer (includes automatic SQL exception translation into Spring’sDataAccessExceptionhierarchy).@Controller/@RestController: Web presentation layer for Spring MVC and REST endpoints.
- Explicit Java-Based Configuration (
@Configuration+@Bean):- Used for instantiating and configuring third-party library classes that cannot be directly annotated with
@Component(e.g.,ObjectMapper,DataSource,WebClient):@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { return new ObjectMapper().findAndRegisterModules(); } }
- Used for instantiating and configuring third-party library classes that cannot be directly annotated with
- Programmatic Functional Registration (Spring 5+):
- Programmatically registers beans at runtime via functional lambdas using
GenericApplicationContext.registerBean(...).
- Programmatically registers beans at runtime via functional lambdas using
🔴 Senior Level
1. Internal Storage: DefaultListableBeanFactory
The engine powering Spring’s IoC container is DefaultListableBeanFactory. It stores metadata and instances in high-performance thread-safe structures (ConcurrentHashMap):
beanDefinitionMap(Map<String, BeanDefinition>): Stores bean metadata specifications.- Three-Level Singleton Cache (
DefaultSingletonBeanRegistry):singletonObjects(Level 1 Cache): Fully initialized, wired, and proxied ready-to-use singleton beans.earlySingletonObjects(Level 2 Cache): Unpopulated raw or early-proxied instances used to resolve circular references.singletonFactories(Level 3 Cache):ObjectFactory<?>instances that lazily generate early references and AOP wrappers.
2. The Bean as an AOP Dynamic Proxy: The final Hazard
In enterprise Spring applications, an injected bean is almost never a raw instance of your class; it is wrapped in an AOP Dynamic Proxy:
Client Invocation ──► [ UserService$$SpringCGLIB$$0 (Proxy) ] ──► [ UserService (Target) ]
│
├── Intercept Call (MethodInterceptor)
├── Open Transaction (@Transactional)
├── Invoke Real Target Method
└── Commit / Rollback Transaction
Spring Boot 2.x and 3.x default to CGLIB proxying (spring.aop.proxy-target-class=true), which creates a runtime subclass of the target bean.
The final Method Catastrophe:
Because CGLIB relies on class inheritance and method overriding:
finalClass: If a class marked with@Transactionalis declaredfinal, CGLIB cannot generate a subclass. Spring crashes at startup withBeanCreationException: Cannot subclass final class.finalMethod: If a method on a bean is declaredfinal:@Service public class PaymentService { @Transactional public final void processPayment() { // DANGER: final method! // Money transfer logic } }Catastrophic Consequence: The application compiles and starts without error! However, Java forbids overriding
finalmethods. When a client callsprocessPayment(), the CGLIB proxy cannot intercept the call. The transaction is never opened, and database mutations execute without transaction boundaries or rollback protection!
3. What Objects Should NEVER Be Spring Beans?
A critical hallmark of a senior engineer is knowing when not to use a framework feature:
- JPA Entities (
@Entity): Entities represent database table rows (User,Order) with mutable state. They have their own lifecycle managed by Hibernate/JPAEntityManagerand must be created via ORM queries ornew. - Data Transfer Objects (DTOs) and Records: DTOs are passive data carriers designed for serialization/deserialization. Making a DTO a Spring bean causes memory bloat and concurrency corruption.
- Value Objects:
Small domain objects (e.g.,
Money,Coordinates,EmailAddress) that represent immutable values. - Short-Lived Request Payloads: Transient objects meant to be quickly garbage-collected should never be managed by the Spring IoC container.
[!NOTE] Spring Beans should be stateless architectural components: services, repositories, controllers, configuration factories, and infrastructure clients.
4 Tricky Questions
1. What is the fundamental difference between an object created via new UserService() and a UserService bean retrieved from the Spring context?
Answer:
An object created via new is a standalone instance in the JVM heap:
- Its internal
@Autowireddependencies remainnull(unless manually passed into a constructor). - Lifecycle callbacks (
@PostConstruct,InitializingBean) are completely ignored. - Enterprise aspect annotations (
@Transactional,@Async,@Cacheable,@PreAuthorize) will not function because the object is not wrapped in a Spring AOP dynamic proxy.
A bean retrieved from the ApplicationContext is fully wired, has executed all initialization lifecycle hooks, and is wrapped in an AOP proxy interceptor that transparently manages transactions, security, and metrics.
2. What happens if you mark a method annotated with @Transactional with the final keyword in Spring Boot?
Answer:
Spring Boot starts successfully without throwing any exception. However, because Spring Boot uses CGLIB dynamic subclassing for AOP proxies by default, the generated proxy subclass cannot override the final method.
When client code invokes this method:
- The invocation bypasses the CGLIB proxy interceptor entirely and executes directly against the raw target class.
- The
TransactionInterceptoris never triggered; no database transaction is opened. - Any exceptions thrown during execution will not trigger a rollback, silently breaking transactional integrity in production.
3. What is a BeanDefinition, when is it generated, and how can it be modified prior to bean creation?
Answer:
A BeanDefinition is an internal Spring interface representing the configuration metadata of a bean (class name, scope, autowiring rules, constructor arguments, properties, and lifecycle method names).
It is generated during the Configuration Scanning Phase (via ASM bytecode inspection of annotated classes or parsing of @Configuration classes), before any bean instances are allocated in the heap.
It can be intercepted and modified dynamically before bean instantiation by implementing the BeanFactoryPostProcessor interface. A prominent example is PropertySourcesPlaceholderConfigurer, which resolves ${property.name} tokens inside BeanDefinition values using environment properties.
4. Why is making JPA Entities (@Entity) Spring Beans considered an antipattern?
Answer:
- Lifecycle Conflict: JPA entities have their own complex lifecycle states (Transient, Managed, Detached, Removed) managed by the Hibernate
EntityManager/ Persistence Context, which clashes with Spring’s singleton bean lifecycle. - Statefulness & Concurrency: JPA entities are stateful representations of specific database rows. Spring Beans are by default singletons shared across all threads; making an entity a singleton bean causes catastrophic data contamination and concurrency race conditions.
- Memory Bloat: An application may process millions of entity rows. Registering each entity in Spring’s
DefaultListableBeanFactorywould cause severe memory leaks and garbage collection thrashing.
🎯 Interview Cheat Sheet
30-Second Elevator Pitch
“A Spring Bean is a standard Java object (POJO) whose complete lifecycle—instantiation, dependency injection, configuration, and destruction—is managed by the Spring IoC Container (
ApplicationContext). The container constructs beans based onBeanDefinitionmetadata blueprints. Beans are typically stateless enterprise components (Services, Repositories, Controllers) and are frequently wrapped in CGLIB dynamic proxies to enable cross-cutting concerns like@Transactionaland@Async. Domain entities, DTOs, and value objects must never be registered as Spring Beans.”
Red Flags & Pitfalls (DO NOT Say)
- ❌ “A Spring Bean is a special class that inherits from a Spring base class.” (Beans are plain POJOs; Spring is non-invasive).
- ❌ “Every class in my project should be annotated with
@Component.” (Entities, DTOs, and records should never be Spring beans). - ❌ “I make my
@Transactionalmethodsfinalto protect them from being altered.” (CGLIB cannot overridefinalmethods, which completely disables transaction interceptors). - ❌ “Instantiating a service with
new MyService()works fine in Spring.” (Creating a bean withnewbypasses Spring DI,@PostConstruct, and AOP proxies).
Architectural Mental Model
From Source Code to Managed Bean:
┌──────────────────────────┐
│ Source Code / Config │ @Service, @Configuration + @Bean
└─────────────┬────────────┘
│ 1. Scan & Parse
▼
┌──────────────────────────┐
│ BeanDefinition │ Metadata Blueprint (Scope, Class, Properties)
└─────────────┬────────────┘
│ 2. BeanFactoryPostProcessor modification
▼
┌──────────────────────────┐
│ Target Object Inst. │ Constructor.newInstance()
└─────────────┬────────────┘
│ 3. DI & Lifecycle Hooks (@PostConstruct)
▼
┌──────────────────────────┐
│ AOP Proxy Wrapper │ CGLIB / JDK Dynamic Proxy (@Transactional)
└─────────────┬────────────┘
│ 4. Stored in Singleton Pool
▼
┌──────────────────────────┐
│ ApplicationContext Ready │ Available for injection into controllers/services
└──────────────────────────┘