Advanced Wiring in Spring Boot

Introduction

Welcome to this lesson on Advanced Bean Wiring in the Spring Framework. In previous lessons, we've established the basics of setting up a Spring Boot project, understanding its structure, managing Spring Beans, and effectively utilizing Dependency Injection (DI) and Bean Scopes.

In this lesson, we will delve into advanced bean wiring techniques in Spring: handling optional dependencies, wiring by name, and injecting collections of beans. By the end of this lesson, you’ll be equipped with the skills to handle complex DI scenarios, making your Spring applications more robust and maintainable.

Handling Optional Dependencies with @Autowired

Sometimes, your beans might depend on other beans that may or may not be available at runtime. In such scenarios, you can make the dependency optional using the @Autowired annotation with required = false.

Consider the following example where dependencies are made optional with @Autowired:

package com.codesignal;

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

@Component
public class SandwichMaker {
    private final Bread bread;
    private final Cheese cheese;

    @Autowired(required = false)
    public SandwichMaker(Bread bread, Cheese cheese) {
        this.bread = bread;
        this.cheese = cheese;
    }

    public void makeSandwich() {
        if (bread != null) {
            System.out.println("Using " + bread.getName());
        } else {
            System.out.println("No bread available");
        }
        
        if (cheese != null) {
            System.out.println("Using " + cheese.getName());
        } else {
            System.out.println("No cheese available");
        }
    }
}

In this example, both the Bread and Cheese beans are marked as optional. If either bean is not defined within the application context, the corresponding field will be null, and the code will gracefully handle its absence.

Handling Optional Dependencies with Java Optional

An alternative and modern approach to handle optional dependencies is using the Optional class, which makes your intention more explicit and your code more readable.

Below is an example of using Java Optional for optional dependency:

package com.codesignal;

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

import java.util.Optional;

@Component
public class SandwichMaker {
    private final Bread bread;
    private final Optional<Cheese> cheese;

    @Autowired
    public SandwichMaker(Bread bread, Optional<Cheese> cheese) {
        this.bread = bread;
        this.cheese = cheese;
    }

    public void makeSandwich() {
        System.out.println("Using " + bread.getName());
        cheese.ifPresent(c -> System.out.println("Using " + c.getName()));
    }
}

In this case, Cheese is wrapped inside an Optional, which elegantly handles its optional nature without requiring explicit null checks, leading to more readable and maintainable code.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal