Every Spring tutorial throws the word "bean" at you within the first minute, rarely stopping to say what one is. The definition is refreshingly simple: a bean is just an object that the Spring container owns instead of your code. The interesting part is how you tell Spring which objects should be beans, and how it names and wires them.
This page covers the two ways to define beans, the stereotype annotations you will use every day, and how the container connects beans together — the practical mechanics behind inversion of control.
A bean is a managed object
When the container starts, it does not manage every class in your project — only the ones you register. Those registered, container-built objects are beans. A bean is not a special type or a subclass of anything; a plain Java class becomes a bean purely because you asked Spring to manage it.
The container keeps one shared instance of each bean by default (singleton scope) and hands
that same instance to everyone who needs it. This is why a @Service you write once is
reused across every request without you creating it again. The different scopes are covered
in Spring bean scopes.
Way one: @Component and component scanning
The most common way to define a bean is to annotate your class with @Component (or a
stereotype) and let component scanning discover it.
import org.springframework.stereotype.Component;
@Component
public class PricingEngine {
public double priceFor(String plan) {
return switch (plan) {
case "basic" -> 999;
case "pro" -> 2499;
default -> 0;
};
}
}
At startup Spring scans the packages under your main application class, finds every class
carrying @Component (directly or through a stereotype), and registers each as a bean. The
default bean name is the class name with a lowercase first letter — so PricingEngine
becomes the bean pricingEngine. You did not write new PricingEngine() anywhere; the
container did.
Component scanning is exactly what makes Spring Boot feel automatic. Boot sets the scan base package to your main class's package, which is why keeping your main class at the root of your package tree matters. The related annotations that drive Boot are collected in Spring Boot annotations.
Stereotype annotations: same bean, clearer intent
@Component works everywhere, but Spring offers specialised versions that also announce a
class's role. They all create beans; they differ in meaning (and occasionally behaviour).
| Annotation | Use it on | Extra meaning |
|---|---|---|
@Component |
Any generic bean | None — the plain base |
@Service |
Business-logic classes | Documents the service layer |
@Repository |
Data-access classes | Adds DB exception translation |
@Controller |
Web MVC controllers | Marks a request handler |
@RestController |
REST endpoints | @Controller + @ResponseBody |
Choosing the right stereotype is not cosmetic. @Repository genuinely adds a behaviour —
translating vendor-specific database exceptions into Spring's consistent
DataAccessException hierarchy. And a reader skimming your code learns the architecture from
the annotations alone.
Pro tip: When an interviewer asks "difference between @Component and @Service", the honest answer is "@Service is a @Component with a semantic role — technically they behave the same for bean creation, but @Repository actually adds exception translation." Naming that one real behavioural difference shows you know the framework, not just the labels.
Way two: @Bean methods in a @Configuration class
Sometimes the class you want as a bean is not yours to annotate — a library type, a
third-party client, an object needing custom construction. For those, write an @Bean
method inside a @Configuration class.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
// The RestTemplate class comes from Spring — you can't put @Component on it,
// so you register it with an @Bean method instead.
@Bean
public RestTemplate restTemplate() {
RestTemplate template = new RestTemplate();
template.setRequestFactory(customFactory());
return template;
}
@Bean
public PricingEngine premiumPricingEngine() {
// full control over how this bean is built
return new PricingEngine();
}
}
Whatever the method returns becomes a bean, and the bean's name is the method name —
restTemplate, premiumPricingEngine. This gives you full control over construction, which
is why configuration classes are where you assemble third-party objects. The rule of thumb:
@Component for classes you own, @Bean for objects you do not.
How beans get wired together
Defining beans is half the story; the container also connects them. When one bean needs another, you inject it, and Spring resolves the reference by type:
@Service
public class CheckoutService {
private final PricingEngine pricingEngine;
// Spring sees CheckoutService needs a PricingEngine bean and injects it
public CheckoutService(PricingEngine pricingEngine) {
this.pricingEngine = pricingEngine;
}
public double totalFor(String plan) {
return pricingEngine.priceFor(plan);
}
}
The container notices CheckoutService requires a PricingEngine, finds the bean it
registered earlier, and passes it into the constructor. No lookup code, no new. The full
set of injection styles — and why constructor injection wins — is in
dependency injection in Spring, and
the underlying principle in inversion of control.
Common mistake: Defining the same logical bean twice — once with
@Componenton the class and again with an@Beanmethod — then wondering why Spring complains about ambiguity or picks the "wrong" one. Register each bean once. If you need two variants, give them distinct names and use@Qualifierat the injection point.
Conditional and profile-based beans
Real applications often need different beans in different situations — a real email sender in production, a fake one in development. Spring lets you register beans conditionally, most commonly with profiles.
@Configuration
public class MailConfig {
@Bean
@Profile("prod") // only becomes a bean when the "prod" profile is active
public EmailSender smtpSender() {
return new SmtpEmailSender();
}
@Bean
@Profile("dev") // active in development instead
public EmailSender consoleSender() {
return new ConsoleEmailSender();
}
}
With the prod profile active the container registers smtpSender; with dev it registers
consoleSender. Any class injecting EmailSender gets whichever one matches the environment,
without a single if in your business code. This is the bean model showing its flexibility:
which object satisfies a dependency can vary, while the code that depends on it never
changes. Profiles are set through configuration such as
application.properties.
Where beans physically live
It is worth being concrete about where beans exist at runtime. When the container starts, it builds each bean and stores it in an internal registry keyed by name and type. When a class needs a dependency, the container looks it up in that registry and injects the stored instance — which, for singletons, is the same object every time.
You can even reach into that registry directly, though you rarely should:
// Ask the container for a bean by type — useful for demos, not everyday code
PricingEngine engine = context.getBean(PricingEngine.class);
Reaching for getBean in application code is usually a sign you are fighting the framework;
let injection supply your dependencies instead. But seeing it clarifies what the container is:
a registry of managed objects you normally access through injection rather than lookup. This
is the same registry the inversion of control container
maintains on your behalf.
Beans have a lifecycle
A bean is not just created and forgotten. The container runs it through a defined sequence: instantiate, inject dependencies, run initialization callbacks, keep it alive for use, then run destruction callbacks at shutdown. You can hook into the init and destroy phases to open resources or clean them up. That whole sequence is covered in the Spring bean lifecycle.
Bringing it together
A Spring bean is an object the container creates, wires and manages — nothing more exotic
than that. You define beans two ways: @Component (and its stereotypes @Service,
@Repository, @Controller) for your own classes discovered by component scanning, and
@Bean methods in a @Configuration class for objects you do not own. Spring names each
bean, resolves dependencies between them by type, and hands out shared singletons by default.
Get comfortable defining beans both ways and explaining the stereotype differences, then move on through the Spring Boot learning hub to bean scopes and the lifecycle. Beans are the vocabulary of Spring — once you speak it fluently, the rest of the framework is just things you can do with beans.
Frequently Asked Questions
What is a Spring bean in simple terms?
What is the difference between @Component and @Bean?
What are stereotype annotations in Spring?
How does Spring name a bean?
Are Spring beans singletons by default?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — Explore the Program

