Constructor-based dependency injection pattern
Dependency injection is a design pattern to resolve the dependencies of dependent classes, and dependencies are nothing but object attributes. The injector has to be constructed for the dependent objects by using one of the ways constructor injection or setter injection. A constructor injection is one of the ways of fulfilling these object attributes at the time of creation to instantiate the object. An object has a public constructor that takes dependent classes as constructor arguments to inject the dependencies. You can declare more than one constructor into the dependent class. Earlier, only the PicoContainer Framework is used a constructor-based dependency injection to resolve dependencies. Currently, the Spring Framework also supports constructor injections to resolve dependencies.
Advantages of the constructor injection pattern
The following are the advantages if you use a constructor injection in your Spring application:
- Constructor-based dependency injection is more suitable for mandatory dependencies, and it makes a strong dependency contract
- Constructor-based dependency injection provides a more compact code structure than others
- It supports testing by using the dependencies passed as constructor arguments to the dependent class
- It favors the use of immutable objects, and does not break the information hiding principle
Disadvantages of constructor injection pattern
The following is the only drawback of this constructor-based injection pattern:
- It may cause circular dependency. (Circular dependency means that the dependent and the dependency class are also dependents on each other, for example, class A depends on Class B and Class B depends on Class A)
Example of constructor-based dependency injection pattern
Let's see the following example for constructor-based dependency injection. In the following code, we have a TransferServiceImpl class, and its constructor takes two arguments:
public class TransferServiceImpl implements TransferService { AccountRepository accountRepository; TransferRepository transferRepository; public TransferServiceImpl(AccountRepository accountRepository,
TransferRepository transferRepository) { this.accountRepository = accountRepository; this.transferRepository = transferRepository; } // ...
}
The repositories will also be managed by the Spring container, and, as such, will have the datasource object for database configuration injected into them by the container, as follows:
Following is the JdbcAccountRepository.java file:
public class JdbcAccountRepository implements AccountRepository{ JdbcTemplate jdbcTemplate; public JdbcAccountRepository(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } // ...
}
Following is the JdbcTransferRepository.java file:
public class JdbcTransferRepository implements TransferRepository{ JdbcTemplate jdbcTemplate; public JdbcTransferRepository(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 also have one argument constructor to inject the dependency with the DataSource class.
Let's see another way of implementing a dependency injection in the enterprise application, which is setter injection.