Setter-based Dependency Injection in Spring

Dependency injection is a design pattern in which a component’s dependencies are supplied externally rather than being hardcoded within the component itself. In Spring, developers mainly use 3 different types of dependency injection:

In this tutorial, we will see how to use Setter-based Dependency Injection to inject a UsersRepository into a UserServiceImpl object.

What is Setter-based Dependency Injection?

Setter-based dependency injection involves setting the dependencies of a component by calling its setter methods, as opposed to using its constructor. This is done by injecting the required dependencies into the component via the setters.

Here is a quick example. I will explain it to you in detail in the following sections below.

@Autowired
public void setUsersRepository(UsersRepository usersRepository) {
  this.usersRepository = usersRepository;
}

UsersRepository JPA Interface

Let’s start by creating the UsersRepository interface.

public interface UsersRepository extends CrudRepository<User, Long> {
}

Setter-based Dependency Injection Example

Next, we will create the UsersServiceImpl class that implements UserService interface. The code example below uses setter-based dependency injection to inject the UsersRepository object.

@Service
public class UserServiceImpl implements UserService {

  private UsersRepository usersRepository;

  @Autowired
  public void setUsersRepository(UsersRepository usersRepository) {
    this.usersRepository = usersRepository;
  }

  @Override
  public void createUser(User user) {
    usersRepository.save(user);
  }
}

In the UserServiceImpl class, we have defined a setter method for UsersRepository named setUsersRepository. The @Autowired annotation is used to tell Spring to automatically inject an instance of UsersRepository into this setter method. This is an example of Setter-based Dependency Injection.

By using setter-based dependency injection, we can manage the dependencies of an object by calling its setter methods. This is particularly useful when you have optional dependencies, as you can simply not call the setter method for that dependency if it’s not required.

Advantages

  1. Flexibility: Setter-based dependency injection provides more flexibility than constructor-based dependency injection, as it allows you to set optional dependencies. You can simply not call the setter method for a particular dependency if it’s not required.
  2. Modularity: Setter-based dependency injection makes it easier to separate concerns in your code. For example, you can use setter-based dependency injection to inject different implementations of a dependency at runtime, which makes it easier to switch between different implementations.
  3. Reusability: With setter-based dependency injection, you can reuse components more easily, as they can be easily swapped with different implementations if necessary.
  4. Testability: Setter-based dependency injection makes it easier to write unit tests for your code, as you can easily replace the dependencies with mock objects for testing purposes.
  5. Easy to understand: Setter-based dependency injection is generally easier to understand for developers who are new to the concept of Dependency Injection.

Disadvantages

  1. Brittle Design: Setter-based dependency injection can lead to a brittle design if not used correctly. For example, if a required dependency is not set, it can result in a NullPointerException at runtime.
  2. Tight coupling: If setter methods are used to set dependencies, the class becomes tightly coupled to the setter methods and the setters must be called in the correct order. This can lead to difficulties in understanding the code, especially if there are many dependencies and the dependencies have complex relationships with one another.
  3. More code: Setter-based dependency injection requires more code than constructor-based dependency injection. You have to write setter methods for each dependency, which can increase the amount of code and make it harder to understand.
  4. Complexity: Setter-based dependency injection can become complex when there are many dependencies, and the dependencies have complex relationships with one another.

Conclusion

In conclusion, setter-based dependency injection should be used with caution. It is important to weigh the advantages and disadvantages of each approach and choose the approach that best fits your needs. If you are using setter-based dependency injection, it is important to design your classes in a way that makes it clear which dependencies are required and which are optional. This can help prevent problems with missing dependencies and make it easier to understand your code.