@Configuration
in Spring Framework: An In-Depth Explanation
The @Configuration
annotation is part of the Spring Framework and is used to mark a class as a source of bean definitions. This annotation is critical in Spring's Java-based configuration, allowing developers to configure the application context without XML.
When a class is annotated with @Configuration
, Spring treats it as a configuration class and processes it to generate and manage Spring Beans. Such classes typically contain one or more methods annotated with @Bean
, which define the beans that should be managed by the Spring container.
Core Concepts of @Configuration
Marks a Class as a Configuration Class
The class becomes a source of bean definitions that Spring will use to set up the application context.Proxy Mechanism
Spring generates a CGLIB-based subclass (proxy) of the class to ensure that@Bean
methods return the same singleton bean instance by default. This behavior is called full mode. If not proxied, calling an@Bean
method multiple times might create multiple instances.Integration with Component Scanning
When used alongside@ComponentScan
(or included in a class annotated with@SpringBootApplication
),@Configuration
-annotated classes can define beans explicitly while letting Spring automatically scan and register others.Allows Dependency Injection
@Configuration
classes support constructor-based or field-based dependency injection to resolve dependencies needed for bean creation.
Basic Example
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
@Bean
public MyController myController() {
return new MyController(myService());
}
}
-
@Bean
Methods: Define the beans explicitly. -
Singleton Behavior: Even though
myController()
callsmyService()
, theMyService
bean is created only once due to proxying.
Best Practices
1. Modular Configuration
Split configuration into multiple classes based on functionality, such as DataConfig
, ServiceConfig
, and WebConfig
. This improves readability and maintainability.
@Configuration
public class DataConfig {
@Bean
public DataSource dataSource() {
// Configure and return the data source
}
}
@Configuration
public class ServiceConfig {
@Bean
public UserService userService() {
return new UserServiceImpl();
}
}
2. Avoid Hardcoding Values
Use external configuration sources like application.properties
or application.yml
and inject values using @Value
or @ConfigurationProperties
.
@Configuration
public class AppConfig {
@Value("${app.name}")
private String appName;
@Bean
public AppService appService() {
return new AppService(appName);
}
}
3. Leverage @ComponentScan
for Scanning
Instead of defining all beans explicitly, use @ComponentScan
to register components like @Service
, @Repository
, and @Component
.
@Configuration
@ComponentScan(basePackages = "com.example.myapp")
public class AppConfig {
// Explicit beans if necessary
}
4. Use Conditional Beans
Define beans conditionally using annotations like @ConditionalOnProperty
or @Profile
to load beans only in specific environments or configurations.
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
// Development data source
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// Production data source
}
}
5. Organize Application Properties
Group configuration properties using @ConfigurationProperties
to minimize scattered @Value
annotations.
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
// Getters and setters
}
What to Watch Out For
-
Avoid Instantiating Beans Manually
Never use
new
to create a bean inside a@Configuration
class, as it bypasses Spring's dependency injection and lifecycle management.
Incorrect:
@Bean
public MyService myService() {
return new MyServiceImpl(); // Manual creation
}
@Bean
public MyController myController() {
return new MyController(new MyServiceImpl()); // Creates a new instance
}
- Circular Dependencies Be cautious when defining beans that depend on each other, as it can lead to circular dependency issues.
Solution: Refactor the code to inject a Provider
or use @Lazy
.
Overloading
@Bean
Methods
Avoid overloading methods annotated with@Bean
as it can lead to unintended results.Proxying Limitations
The proxy mechanism of@Configuration
works only if the class is notfinal
. Avoid marking configuration classes asfinal
.Use
@Component
Wisely
Avoid mixing@Component
and@Configuration
in the same class. This can lead to unexpected behavior as@Configuration
is processed differently.
Advanced Example with Dependency Injection
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://localhost:3306/mydb")
.username("user")
.password("password")
.build();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public UserRepository userRepository(JdbcTemplate jdbcTemplate) {
return new UserRepositoryImpl(jdbcTemplate);
}
@Bean
public UserService userService(UserRepository userRepository) {
return new UserServiceImpl(userRepository);
}
}
- Dependency Injection: Each bean depends on another and Spring resolves dependencies automatically.
-
Reusable Beans: Beans like
DataSource
andJdbcTemplate
are reusable across multiple services.
Summary
-
Purpose:
@Configuration
enables defining beans in a centralized and type-safe manner. -
Best Practices: Modularize configuration, use externalized properties, and leverage Spring's annotations like
@Profile
and@Conditional
. -
Pitfalls to Avoid: Instantiating beans manually, circular dependencies, overloading
@Bean
methods, and usingfinal
with@Configuration
.
By following these practices, you can use @Configuration
effectively to build robust and maintainable Spring applications.
Top comments (0)