The Spring Framework offers powerful dependency injection features that simplify Java application development. Two commonly used annotations in Spring are @Bean
and @Autowired
.
In this article, we’ll explore what each annotation does, how they work together, and walk through a full working example.
What is @Bean
?
The @Bean
annotation tells Spring that a method will return an object that should be registered as a bean in the Spring application context. It’s typically used within a class annotated with @Configuration
.
Basic Example
Let’s say we have a simple UserRepository
class that provides user data.
UserRepository.java
public class UserRepository {
public String getUser() {
return "John Doe";
}
}
Now, we want to define this class as a Spring-managed bean.
AppConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}
When the Spring application starts, it will register a UserRepository
bean in its context.
What is @Autowired
?
The @Autowired
annotation tells Spring to automatically inject a bean where it’s required. It can be used on constructors, fields, or setter methods.
This works especially well with beans defined using @Bean
.
Using @Autowired
with Constructor Injection
Let’s add a UserService
that depends on UserRepository
.
UserService.java
import org.springframework.beans.factory.annotation.Autowired;
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public String getUserInfo() {
return "User Info: " + userRepository.getUser();
}
}
This constructor tells Spring to inject an instance of UserRepository
into UserService
.
Wiring it All Together with @Bean
and @Autowired
We now define both beans in our configuration class:
Updated AppConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
}
Even though we are using @Autowired
in the UserService
constructor, Spring will automatically inject the UserRepository
bean we declared.
Running the Application
Application.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
System.out.println(userService.getUserInfo());
}
}
Output:
pgsqlCopyEditUser Info: John Doe
Best Practices
- Use
@Bean
when you need fine-grained control over bean creation. - Prefer constructor-based injection with
@Autowired
for better testability and immutability. - Avoid field injection if possible; it’s less flexible and harder to test.
Conclusion
Spring’s @Bean
and @Autowired
annotations work hand in hand to provide flexible and powerful dependency injection. With these tools, you can easily manage object creation and wiring, making your code cleaner, modular, and testable.