Have you come across @Configuration or @Bean while developing with Spring Boot?
They are a common source of confusion: “How is this different from @Component?” and “Where is the right place to use it?”
This article explains the roles and usage of @Configuration / @Bean with concrete examples.
This article covers Java Configuration (defining Beans via @Configuration classes and @Bean methods). This is separate from the “application configuration values” written in application.properties / application.yml, so if you are looking for the configuration file side, please refer to that article instead.
After reading this article, you will be able to make the following decisions:
- Whether to write
@Componentor@Configuration+@Bean - The standard pattern for using classes from external libraries via DI
- The behavioral differences that occur when you forget
@Configuration, and how to avoid them
What is @Configuration?
@Configuration is an annotation that tells Spring “this class is a configuration class.”
Inside a configuration class, you define @Bean methods and assemble the objects (Beans) you want to register with the Spring container.
Conceptually, @Configuration provides “a place to write, in one spot, how Beans are created.”
What is @Bean?
@Bean is an annotation that you attach to a method, and it registers the method’s return value as a Bean in the Spring container.
Whereas @Component is “attached to a class to register the class itself as a Bean,” the key difference is that @Bean “registers the object returned by the method as a Bean.”
Typical cases where @Bean shines include:
- You want to register a class you didn’t write yourself (from an external library) as a Bean
- The creation process is somewhat complex and can’t be done with a simple
new - You want to combine configuration values or dependent Beans at creation time
Basic Usage (Sample)
For example, suppose you want to register the external library class Clock as a Bean. Since you can’t attach @Component to the class, this is where @Bean comes in.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Clock;
@Configuration
public class AppConfig {
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
}
With this, Clock is registered in the Spring container and can be injected into other classes via DI.
import org.springframework.stereotype.Service;
import java.time.Clock;
@Service
public class TimeService {
private final Clock clock;
public TimeService(Clock clock) {
this.clock = clock;
}
}
Commonly Used Techniques
Specifying the Bean Name
By default, the method name becomes the Bean name.
If you want to specify it explicitly, you can do so as follows:
@Bean("systemClock")
public Clock clock() {
return Clock.systemDefaultZone();
}
Receiving Dependencies via @Bean Method Parameters (This Is Handy)
For @Bean methods, you simply declare the Beans you need as parameters, and Spring resolves and passes them in.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyClient myClient(MyProperties props, Clock clock) {
return new MyClient(props.getEndpoint(), clock);
}
}
This is where the benefit of using @Configuration as “the place to assemble Beans” really shows.
The same form applies when you want to use configuration values from application.yml: the typical pattern is to receive a configuration class annotated with @ConfigurationProperties as a parameter and assemble the Bean using its values. This is how Java Configuration and application configuration work together.
Changing the Scope (Only When Needed)
The default is singleton (one instance per application), but depending on the use case, you may sometimes use prototype or others.
import org.springframework.context.annotation.Bean;
import org.framework.context.annotation.Scope;
@Bean
@Scope("prototype")
public SomeObject someObject() {
return new SomeObject();
}
(That said, in typical business applications, singleton is used almost all the time.)
Common Pitfalls
1) Behavioral Differences Due to @Configuration’s “Proxy”
Classes annotated with @Configuration are internally proxied, so that calls between @Bean methods are adjusted to return the “same Bean.”
Therefore, in code like the following, a() is not new-ed every time; instead, the same container-managed instance is generally returned.
@Configuration
public class AppConfig {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
return new B(a()); // calling a()
}
}
Conversely, if you don’t attach @Configuration (or depending on the settings), this behavior changes and becomes a source of confusion.
In the beginning, remembering “if you write @Bean, just put it in a @Configuration class” will reduce accidents.
2) Can @Bean Be Used Without @Configuration?
The short answer is yes, it can. However, there is a prerequisite.
Prerequisite: The Class Itself Must Be Managed by Spring
@Bean only has meaning when written inside “a class that Spring picks up.”
In other words, as long as the class itself is registered as a Bean, as in the following situations, @Bean works even without @Configuration:
- The class is annotated with
@Component - The class is component-scanned under
@SpringBootApplication(or is@Import-ed) - The class is explicitly loaded as Java Config
Example: @Bean also works with @Component.
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.time.Clock;
@Component
public class AppConfig {
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
}
In this case as well, Clock is registered as a Bean in the Spring container.
However, @Configuration Is Safer
When @Configuration is present, the configuration class enters “full mode (CGLIB proxy),” and even when @Bean methods call each other, the same container-managed Bean is more reliably returned.
Conversely, with @Component or similar and no @Configuration, @Bean methods are treated as plain method calls, and depending on the situation, separate instances may be created.
For this reason, if you are writing a configuration class, it is safest to attach @Configuration as a rule.
3) Don’t Force @Bean Where @Component Would Suffice
If it’s your own class, creation is simple, and it can normally be a component scan target, then @Component / @Service / @Repository and the like are sufficient.
@Bean is effective when “you can’t annotate the class” or “creation is somewhat special.”
Practical Rules for When You’re Unsure
If you’re unsure about the boundary between @Component and @Bean, deciding based on the following will keep things consistent.
| Situation | Recommendation | Reason |
|---|---|---|
| Want to register your own class as-is | @Component family | Simple and readable |
| Want to register an instance from an external library | @Configuration + @Bean | The class can’t be annotated |
| Need conditional branching or configuration assembly at creation | @Configuration + @Bean | Initialization logic can be made explicit |
| Want to define multiple Beans of the same type and use them for different purposes | @Bean + @Qualifier | Safe, name-based selection |
Giving configuration classes the role of a “wiring diagram for dependent objects” makes the design easier to read.
Tips for Making Beans Easy to Swap in Tests
@Bean definitions also work well with swapping during tests.
For example, if you turn an external API client into a Bean, it becomes easy to replace it with @TestConfiguration or @MockBean.
@TestConfiguration
public class TestClientConfig {
@Bean
public ApiClient apiClient() {
return new ApiClient("http://localhost:9999");
}
}
Compared to a design that directly news the production implementation, switching between test and production can be done more safely.
Operational Considerations
- If you specify Bean names explicitly, establish a naming convention (e.g.,
xxxClient,xxxClock) - Don’t overuse conditional Beans (
@ConditionalOnProperty, etc.) - Split configuration classes when the dependency graph becomes complex
Turning a configuration class into a “place to put anything” quickly makes it hard to read, so splitting by domain is effective.
Summary
@Configurationis “a configuration class that gathers together how Beans are created”@Bean“registers a method’s return value as a Bean in the Spring container”@Beanis especially useful when you want to inject external library classes via DI or when creation is complex- @Bean can be used without @Configuration (provided the class is managed by Spring)
- However, if you’re writing a configuration class, operating with @Configuration attached is less accident-prone