Setter-based dependency injection

The injector of the container has another way to wire the dependency of the dependent object. In setter injection, one of the ways to fulfil these dependencies is by providing a setter method in the dependent class. Object has a public setter methods that takes dependent classes as method arguments to inject dependencies. For setter-based dependency injection, the constructor of the dependent class is not required. There are no changes required if you change the dependencies of the dependent class. Spring Framework and PicoContainer Framework support setter injection to resolve the dependencies.

Advantages of setter injection

The following are the advantages if you use the setter injection pattern in your Spring application:

  • Setter injection is more readable than the constructor injection
  • Setter injection solves the circular dependency problem in the application
  • Setter injection allows costly resources or services to be created as late as possible, and only when required
  • Setter injection does not require the constructor to be changed, but dependencies are passed through public properties that are exposed

Disadvantage of the setter injection

The following are the drawbacks of the setter injection pattern:

  • Security is lesser in the setter injection pattern, because it can be overridden
  • A setter-based dependency injection does not provide a code structure as compact as the constructor injection
  • Be careful whenever you use setter injection, because it is not a required dependency

Example of a setter-based dependency injection

Let's see the following example for setter-based dependency injection. The following TransferServiceImpl class, has setter methods with one argument of the repository type:

Following is the TransferServiceImpl.java file:

    public class TransferServiceImpl implements TransferService { 
      AccountRepository accountRepository; 
      TransferRepository transferRepository; 
    
      public void setAccountRepository(AccountRepository 
accountRepository) { this.accountRepository = accountRepository; } public void setTransferRepository(TransferRepository
transferRepository) { this.transferRepository = transferRepository; } // ... }

Similarly, let's define a setter for the repositories' implementations as follows:

Following is the JdbcAccountRepository.java file:

    public class JdbcAccountRepository implements AccountRepository{ 
      JdbcTemplate jdbcTemplate; 
      public setDataSource(DataSource dataSource) { 
        this.jdbcTemplate = new JdbcTemplate(dataSource); 
    } 
     // ... 
   } 

Following is the JdbcTransferRepository.java file:

    public class JdbcTransferRepository implements TransferRepository{ 
      JdbcTemplate jdbcTemplate; 
      public setDataSource(DataSource dataSource) { 
        this.jdbcTemplate = new JdbcTemplate(dataSource); 
   } 
    // ... 
  } 

You can see in the preceding code the JDBC implementation of the repositories as AccountRepository and TransferRepository. These classes have a setter method with one argument to inject the dependency with the DataSource class.

Constructor versus setter injection and best practices

The Spring Framework provides support for both types of dependency injection patterns. Both, the constructor and setter injection pattern, assemble the elements in the system. The choice between the setter and constructor injections depends on your application requirement, and the problem at hand. Let's see the following table, which lists some differences between the constructor and setter injections, and some best practices to select which one is suitable in your application.

 

In the next section, you'll learn how to configure the injector to find the beans and wire them together, and how the injector manages the beans. Here, I will use the Spring configuration for the dependency injection pattern.