CodeGym /Courses /Module 5. Spring /Practice: annotations @Component, @Autowired, @Bean

Practice: annotations @Component, @Autowired, @Bean

Module 5. Spring
Level 2 , Lesson 4
Available

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.

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION