Spring Dependency Injection using @Autowired

Introduction

In this tutorial we will exemplify how to use Spring Context library to resolve Dependency Injection using annotations in a simple Gradle multi-layer application.

What do we create?

Dependency Injection is a design pattern that allows objects to inject their dependencies from an external source, rather than creating them directly within the object.

This pattern promotes loose coupling, easier testing, and more modular code by decoupling the creation and management of dependencies from the object that uses them.

Java frameworks like Spring provide built-in dependency injection to handle this complexity. For instance, Spring’s Inversion of Control (IoC) container manages the instantiation and injection of dependencies for you.

We will create a simple multi-layer application and we will use Spring Context library to solve the dependency injection.

How do we create it?

First, we should create a new Gradle Project. In the build.gradle file, we need to add Spring context dependency and ‘application’ plugin to simplify the execution of our application.

				
					plugins {
    id 'java'
    id 'application'
}

group 'org.explainjava'
version '1.0'

repositories {
    mavenCentral()
}

application {
    mainClassName = "org.explainjava.Main"
}

dependencies {
    implementation 'org.springframework:spring-context:6.1.14'
}

test {
    useJUnitPlatform()
}
				
			

A multi-layer application is a software architecture pattern that separates an application into distinct layers, each with specific responsibilities.

Typically, a multi-layer Java application includes at least three main layers: Repository, Service, and UI.

Let’s create a simple example of a multi-layer application where users can manage “Lemonade” records (add and list lemonades) in an inventory.

First of all, we need to create the Lemonade entity:

				
					public class Lemonade {
    
    private Long id;
    
    private String name;
    
    private double price;

    public Lemonade() {
    }

    public Lemonade(Long id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

   // getters and setters
}
				
			

 

Then, we should create a simple in-memory repository class to keep track of our Lemonades. 

In the context of the Spring Framework, a bean is simply a Java object that is instantiated, assembled, and managed  by the Spring container. Beans are the core building blocks of any Spring application.

 

When the application starts, Spring creates an application context, loads configuration, and then creates and initializes beans as specified in the configuration.

 

Common annotations to define beans are @Component, @Service, @Repository, and @Controller. You can also explicitly define beans using the @Bean annotation in a @Configuration class.

The @Repository annotation in Spring is a specialization of the @Component annotation, used to indicate to Spring Framework that the annotated class is a Repository bean.

				
					@Repository
public class LemonadeRepository {
    private Map<Long, Lemonade> lemonades;

    public LemonadeRepository() {
        this.lemonades = new HashMap<>();
    }

    public Lemonade save(Lemonade lemonade) {
        this.lemonades.put(lemonade.getId(), lemonade);
        return lemonade;
    }

    public Iterable<Lemonade> findAll() {
        return this.lemonades.values();
    }

}
				
			

The next step is to create the service layer of our application. The service layer will use the repository to handle business logic. It calls the repository methods to retrieve or add lemonades.

We will use @Autowired annotation. It allows Spring to automatically “inject” the necessary dependencies (objects or beans) into a class, rather than requiring you to manually create or pass those dependencies.

				
					@Service
public class LemonadeService {

    @Autowired
    private LemonadeRepository lemonadeRepository;

    public Iterable<Lemonade> getAllLemonades() {
        return lemonadeRepository.findAll();
    }

    public Lemonade getLemonadeById(Long id) {
        return lemonadeRepository.findById(id);
    }

    public Lemonade addLemonade(Lemonade product) {
        return lemonadeRepository.save(product);
    }
}
				
			

Finally, we should create a test main class:

				
					public class Main {

      public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.explainjava");
        context.refresh();

        LemonadeService lemonadeService = context.getBean(LemonadeService.class);

        lemonadeService.addLemonade(new Lemonade(1L, "Sweet Lemonade", 10));

        Iterable<Lemonade> lemonades = lemonadeService.getAllLemonades();
        for(Lemonade lemonade : lemonades){
            System.out.println(lemonade);
        }
    }
    
}
				
			

You can check the project structure below:

spring dependency injection project structure

Conclusion

In this tutorial we had a simple example of how to use Spring Context library to resolve Dependency Injection in a simple Gradle multi-layer application.