Spring Dependency Injection with java Configuration

Introduction

In this tutorial we will exemplify how to use Spring Context library to resolve Dependency Injection using XML configuration 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 can create a simple in-memory repository class to keep track of our Lemonades. 

				
					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.

				
					public class LemonadeService {

    private LemonadeRepository lemonadeRepository;

    public LemonadeService(LemonadeRepository lemonadeRepository) {
        this.lemonadeRepository = lemonadeRepository;
    }

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

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

Now, let’s create the Java configuration file, which defines the beans and sets up the dependency injection.

In the Spring Framework, a bean is a Java object that the Spring container instantiates, assembles, and manages. Beans serve as the fundamental building blocks of any Spring application.

				
					@Configuration
public class AppConfig {

    @Bean
    public LemonadeRepository lemonadeRepository() {
        return new LemonadeRepository();
    }

    @Bean
    public LemonadeService lemonadeService() {
        return new LemonadeService(lemonadeRepository());
    }
}
				
			

The structure of the project should look like this:

spring dependency injection project structure java config

The Main class will load the Spring configuration, retrieve the LemonadeService bean, and interact with it.

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

				
					public class Main {

        public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        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.getName());
        }
    }
}
				
			

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 with Java Configuration.