How do I use @Component, @Autowired, and @Qualifier in Spring?

Spring provides annotations like @Component, @Autowired, and @Qualifier to simplify dependency injection and make applications loosely coupled and modular. Below, we’ll explore these annotations in detail, focusing on their usage and a complete example.

1. @Component Annotation

The @Component annotation marks a class as a Spring-managed bean. It is auto-detected during component scanning, and Spring adds it to the application context.

Usage:

import org.springframework.stereotype.Component;

@Component
public class ExampleComponent {
    public void execute() {
        System.out.println("Component is working!");
    }
}

When the Spring application starts, it automatically scans the classpath for classes annotated with @Component (and its specializations like @Service, @Repository, and @Controller) and registers them as beans in the application context.

2. @Autowired Annotation

The @Autowired annotation is used for automatic dependency injection. It instructs Spring to inject a matching bean from the application context where the annotation is applied.

Types of Injection:

  1. Field Injection:
    @Component
    public class ClientWithFieldInjection {
       @Autowired
       private ExampleComponent exampleComponent;
    
       public void perform() {
           exampleComponent.execute();
       }
    }
    
  2. Setter Injection:
    @Component
    public class ClientWithSetterInjection {
       private ExampleComponent exampleComponent;
    
       @Autowired
       public void setExampleComponent(ExampleComponent exampleComponent) {
           this.exampleComponent = exampleComponent;
       }
    
       public void perform() {
           exampleComponent.execute();
       }
    }
    
  3. Constructor Injection (Preferred):
    @Component
    public class ClientWithConstructorInjection {
       private final ExampleComponent exampleComponent;
    
       @Autowired
       public ClientWithConstructorInjection(ExampleComponent exampleComponent) {
           this.exampleComponent = exampleComponent;
       }
    
       public void perform() {
           exampleComponent.execute();
       }
    }
    
  • Preferred: Constructor injection is considered a best practice because:
    • Dependencies are initialized during object creation, ensuring immutability.
    • It’s easier to write unit tests, as all dependencies can be provided explicitly.

3. @Qualifier Annotation

When multiple beans of the same type exist in the application context, Spring must decide which one to inject. By default, it uses the bean name, but you can explicitly specify which bean to use with the @Qualifier annotation.

Complete Example with Interface, Implementations, and Dependency Injection

Step 1: Define an Interface

Create an abstraction to represent a service contract.

public interface ServiceA {
    void serve();
}

Step 2: Provide Implementations

Implement the ServiceA interface with two different classes.

import org.springframework.stereotype.Component;

@Component("serviceAImpl1")
public class ServiceAImpl1 implements ServiceA {
    @Override
    public void serve() {
        System.out.println("ServiceAImpl1 is serving...");
    }
}

@Component("serviceAImpl2")
public class ServiceAImpl2 implements ServiceA {
    @Override
    public void serve() {
        System.out.println("ServiceAImpl2 is serving...");
    }
}
  • The @Component("serviceAImpl1") and @Component("serviceAImpl2") annotations allow Spring to identify and differentiate the two beans. The specified names (serviceAImpl1 and serviceAImpl2) can be used with the @Qualifier annotation.

Step 3: Inject the Dependency in the Client Class

Create a client class that depends on ServiceA.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Client {
    private final ServiceA serviceA;

    @Autowired
    public Client(@Qualifier("serviceAImpl1") ServiceA serviceA) { // Use serviceAImpl1
        this.serviceA = serviceA;
    }

    public void run() {
        serviceA.serve();
    }
}
  • @Qualifier("serviceAImpl1"): Ensures that the specific implementation ServiceAImpl1 is injected into the Client class. Without the qualifier, Spring would throw an error due to ambiguity, as multiple beans (serviceAImpl1 and serviceAImpl2) implement the same interface.

Step 4: Application Entry Point

Run the application with @SpringBootApplication to trigger Spring’s component scanning and dependency injection.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        var context = SpringApplication.run(Application.class, args);

        // Get the client bean from the Spring application context
        Client client = context.getBean(Client.class);
        client.run(); // This will call ServiceAImpl1's serve() method.
    }
}

How It Works

  1. Component Scanning:
    • Spring automatically scans for all classes annotated with @Component and registers them as beans in the application context.
  2. Dependency Injection:
    • Spring injects ServiceAImpl1 into Client using the @Autowired and @Qualifier annotations.
  3. Output: Upon running the application, the following message is printed:

ServiceAImpl1 is serving...

Key Advantages of Using Interfaces and Dependency Injection

  • Loose Coupling: The client depends on an abstraction (ServiceA) rather than concrete classes, making the application flexible and easier to maintain.
  • Testability: By using interfaces, you can easily mock or stub dependencies for testing purposes.
  • Flexibility: New implementations can be added and swapped out without changing the client code.

Additional Notes on @Qualifier

  • If only one implementation exists, you don’t need @Qualifier; Spring can find the appropriate bean automatically.
  • If you don’t use @Qualifier, and there are multiple matching beans, Spring throws a NoUniqueBeanDefinitionException.

Final Thoughts

Using @Component, @Autowired, and @Qualifier together allows you to create a clean and modular structure in Spring applications. By programming to an interface, following the best practice of constructor injection, and leveraging qualifiers for resolving ambiguities, you can develop highly extensible and maintainable applications.


Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.2.6</version>
    </dependency>
</dependencies>

Maven Central

How do I define and inject dependencies using annotations in Spring?

In Spring, you can define and inject dependencies using annotations, which simplifies the process of configuring beans and their relationships. Here’s how you can do it step by step:


1. Define a Dependency with @Component

To define a class as a Spring-managed component (or bean), you annotate it with @Component, which makes the class eligible for dependency injection.

package org.kodejava.spring;

import org.springframework.stereotype.Component;

@Component
public class MyDependency {
    public void doSomething() {
        System.out.println("Dependency logic executed.");
    }
}

Here, @Component tells Spring to manage the lifecycle of this class as a bean.


2. Inject the Dependency with @Autowired

You can inject dependencies into another class by using the @Autowired annotation. It can be applied to:

  • Field injection
  • Constructor injection (recommended)
  • Setter injection

A. Field Injection

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired // Spring automatically injects the MyDependency bean here
    private MyDependency myDependency;

    public void performTask() {
        myDependency.doSomething();
    }
}

B. Constructor Injection (Recommended)

Constructor injection is preferred as it makes the dependencies immutable and facilitates better testing.

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    private final MyDependency myDependency;

    @Autowired
    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void performTask() {
        myDependency.doSomething();
    }
}

Note: From Spring 4.3 onward, if a class has only one constructor, the @Autowired annotation is optional since Spring will automatically use that constructor to inject dependencies.


C. Setter Injection

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    private MyDependency myDependency;

    @Autowired
    public void setMyDependency(MyDependency myDependency) {
        this.myDependency = myDependency;
    }

    public void performTask() {
        myDependency.doSomething();
    }
}

3. Marking Other Components

Instead of using @Component, Spring provides additional stereotype annotations for specific roles, although they work similarly. These are:

  • @Service: Used for service classes.
  • @Repository: Used for data access/DAO components.
  • @Controller: Used for Spring MVC controllers.

Example:

import org.springframework.stereotype.Service;

@Service
public class MyService {
    public void executeService() {
        System.out.println("Executing service logic...");
    }
}

4. Enable Component Scanning

To ensure Spring automatically discovers and registers your components, you need to enable component scanning using the @ComponentScan annotation in your configuration class.

Example configuration class:

package org.kodejava.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "org.kodejava")
public class AppConfig {
}

Alternatively, if you are using Spring Boot, component scanning is enabled automatically for classes within the same package or sub-packages of the main application class annotated with @SpringBootApplication.


5. Example of Application Setup

Here’s a complete example:

Dependency

package org.kodejava.spring;

import org.springframework.stereotype.Component;

@Component
public class HelloWorldService {
    public String sayHello() {
        return "Hello, World!";
    }
}

Service

package org.kodejava.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GreetingService {
    private final HelloWorldService helloWorldService;

    @Autowired
    public GreetingService(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }

    public void printGreeting() {
        System.out.println(helloWorldService.sayHello());
    }
}

Main Application

package org.kodejava.spring;

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);

        GreetingService greetingService = context.getBean(GreetingService.class);
        greetingService.printGreeting();
    }
}

Configuration

package org.kodejava.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "org.kodejava")
public class AppConfig {
}

Summary of Annotations:

  • @Component: Marks a class as a Spring bean.
  • @Service: A specialization of @Component, typically used for service-layer classes.
  • @Repository: A specialization of @Component, used for DAO/repository classes.
  • @Controller: A specialization of @Component, used for Spring MVC controllers.
  • @Autowired: Marks a dependency to be automatically injected by Spring.
  • @ComponentScan: Specifies the base package(s) for scanning components.

This approach makes dependency management clean and reduces boilerplate code compared to XML-based configurations.


Maven Dependencies

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.6</version>
</dependency>

Maven Central