Now let's get hands-on with annotations so things make more sense.
1. The @Component annotation — the magic of bean creation
The @Component annotation turns a regular Java class into a Spring Bean that's automatically managed by the Spring IoC container. It's like telling some Spring special agent: "Watch this class, create its instance and inject it when needed."
Under the hood the IoC container scans project classes using the Component Scan mechanism and looks for all classes annotated with @Component.
Example of using @Component
import org.springframework.stereotype.Component;
// This annotation shows that this class is a component (bean)
@Component
public class CoffeeMaker {
public String makeCoffee() {
return "☕ Coffee is ready!";
}
}
Now CoffeeMaker is registered in the IoC container. You can get it anywhere, and Spring will create an instance of this class for you.
Analogy: if you were the Spring container, @Component is a sign that says "Add this to my list of responsibilities".
2. The @Autowired annotation: the art of dependency injection
When we mark something with @Autowired, we tell Spring: "Find and wire the right component yourself!". Spring finds a suitable bean (for example, our CoffeeMaker) and injects it via a field, constructor, or setter.
Field injection
This way is the simplest, but it has enough drawbacks (see "Common mistakes" below).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
// Tell Spring: "Inject CoffeeMaker here!"
@Autowired
private CoffeeMaker coffeeMaker;
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
By marking the field with @Autowired, we told Spring that it must be initialized before the first call. Now, when we run the application, Barista will know how to serve coffee.
Constructor injection
The recommended way: it makes dependencies "visible" and easy to test.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
private final CoffeeMaker coffeeMaker;
// Spring will call this constructor and pass CoffeeMaker
@Autowired
public Barista(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Setter injection
Useful if dependencies can change at runtime (rarely needed, but just in case).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Barista {
private CoffeeMaker coffeeMaker;
@Autowired
public void setCoffeeMaker(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Tip: if a dependency is required, use a constructor. If it's optional — use a setter.
3. The @Bean annotation — creating custom beans
The @Bean annotation is used to explicitly tell Spring that a method in a configuration class creates a bean. This approach is especially useful if you can't or don't want to modify the original class (for example, if it's from a third-party library).
Example of using @Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// Indicate that this class is a Java configuration
@Configuration
public class CoffeeConfig {
// This method creates a CoffeeMaker object
@Bean
public CoffeeMaker coffeeMaker() {
return new CoffeeMaker();
}
}
Now, instead of @Component, we've explicitly declared that the CoffeeMaker class is created via the coffeeMaker method. Spring will still add it to the IoC container.
4. Practical use of all annotations together
Now let's put everything together into a small application.
Class 1: CoffeeMaker
import org.springframework.stereotype.Component;
@Component
public class CoffeeMaker {
public String makeCoffee() {
return "☕ Coffee is ready!";
}
}
Class 2: Barista
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
public class Barista {
private final CoffeeMaker coffeeMaker;
@Autowired
public Barista(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker;
}
public void serveCoffee() {
System.out.println(coffeeMaker.makeCoffee());
}
}
Class 3: CoffeeShopConfig (using @Bean)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CoffeeShopConfig {
@Bean
public String coffeeRecipe() {
return "Coffee recipe: take coffee, add water and love!";
}
}
Main class to run
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class CoffeeShopApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(CoffeeShopApplication.class, args);
// Get Barista from the IoC container
Barista barista = context.getBean(Barista.class);
barista.serveCoffee();
// The bean with the coffee recipe is also available
String recipe = context.getBean(String.class);
System.out.println(recipe);
}
}
5. Common mistakes and how to avoid them
Missing bean
If you don't mark a class with @Component or don't define a method with @Bean, Spring won't add it to the IoC container. As a result you'll get NoSuchBeanDefinitionException.
Multiple candidates for @Autowired
When Spring finds two beans of the same type, it doesn't know which one to use. @Qualifier helps here.
@Autowired
@Qualifier("specialCoffeeMaker")
private CoffeeMaker coffeeMaker;
Unavailable dependencies
If you try to inject dependencies via a field, but it's declared private and there's no constructor or setter, Spring won't be able to perform DI. The solution is obvious: use either constructors or setters.
Now you know how to work with the @Component, @Autowired and @Bean annotations. These basics are the foundation for writing flexible and modular applications in the Spring Framework. Now it's up to practice.
GO TO FULL VERSION