Spring Constructor Dependency Injection Example

A guide to Spring Constructor Dependency Injection Example.

Overview

The constructor-based Dependency Injection is a type of Spring Dependency Injection. The other type of dependency injection is Setter Injection & Field Injection.

Constructor Based Dependency Injection

It is a type of Spring Dependency Injection where an object’s constructor injects dependencies. This type of injection is safer as the objects won’t be created if the dependencies aren’t available or cannot be resolved.

To understand how the constructor-based Dependency Injection works in Spring, we need a Spring Application. Consider we have a straightforward Spring Application called DogsService.

Don’t know how to write Spring Boot Rest Service?
Read this:Spring Boot Rest Service

The Dogs DAO

The DAO class doesn’t have any dependency. We have added a no-argument constructor with a print statement.

import com.amitph.spring.dogs.repo.Dog;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class DogsDao {
  public DogsDao(){
    System.out.println("DogsDao no-arg constructor called");
  }
  public List<Dog> getAllDogs() {
    System.out.println("DogsDao.getAllDogs called");
    return null;
  }
}Code language: Java (java)

The Dogs Service

The Service HAS-A DogsDao. The service class has a setter method, a no-argument constructor, and a parameterised constructor with respective print statements.
Note: The parameterised constructor is annotated with @Autowrired.

import com.amitph.spring.dogs.dao.DogsDao;
import com.amitph.spring.dogs.repo.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class DogsService {
  private DogsDao dao;

  public List<Dog> getDogs() {
    System.out.println("DogsService.getDogs called");
    return dao.getAllDogs();
  }

  public void setDao(DogsDao dao) {
    System.out.println("DogsService setter called");
    this.dao = dao;
  }

  public DogsService(){
    System.out.println("DogsService no-arg constructor called");
  }

  @Autowired
  public DogsService(DogsDao dao) {
    System.out.println("DogsService arg constructor called");
    this.dao = dao;
  }
}Code language: Java (java)

The Dogs Controller

The Controller HAS-A DogsService. The controller class also has one setter, a no-argument constructor and a parameterised constructor with respective print statements.
Note: The parameterised constructor is annotated with @Autowired.

import com.amitph.spring.dogs.repo.Dog;
import com.amitph.spring.dogs.service.DogsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/dogs")
public class DogsController {
  private DogsService service;

  @GetMapping
  public List<Dog> getDogs() {
    return service.getDogs();
  }

  public void setService(DogsService service) {
    System.out.println("DogsController setter called");
    this.service = service;
  }

  public DogsController(){
    System.out.println("DogsController no-arg constructor called");
  }

  @Autowired
  public DogsController(DogsService service) {
    System.out.println("DogsController arg constructor called");
    this.service = service;
  }
}Code language: Java (java)

Run The Application

When we start the application, we should see the below logs on the console.

INFO [main] com.amitph.spring.dogs.Application       : Starting Application on Amitsofficemac.gateway with PID 68906 (/Users/aphaltankar/Workspace/personal/dog-service-jpa/out/production/classes started by aphaltankar in /Users/aphaltankar/Workspace/personal/dog-service-jpa)
INFO [main] com.amitph.spring.dogs.Application       : No active profile set, falling back to default profiles: default
INFO [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
INFO [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 45ms. Found 1 repository interfaces.
INFO [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$86296a04] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO [main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO [main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/9.0.12
INFO [main] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/aphaltankar/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
INFO [main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO [main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1158 ms
INFO [main] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
INFO [main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
INFO [main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
INFO [main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'formContentFilter' to: [/*]
INFO [main] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
INFO [main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
INFO [main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
INFO [main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default...]
INFO [main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.3.7.Final}
INFO [main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
INFO [main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
INFO [main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
INFO [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
DogsDao no-arg constructor called
DogsService arg constructor called
DogsController arg constructor called
INFO [main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
WARN [main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
INFO [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
INFO [main] com.amitph.spring.dogs.Application       : Started Application in 3.003 seconds (JVM running for 3.521)Code language: plaintext (plaintext)
  • Line #27: As expected, the no-argument constructor of DAO is called.
  • Line #28: A parameterised constructor DogsService is called along with an instance of DAO created at line #27.
  • Line #29: A parameterised constructor of the controller is invoked along with a service instance created at line #28.

Notice here that neither the setters nor the no-argument constructors were invoked by Spring. The dependencies were injected purely using Constructors. This approach is preferred over Spring Setter Injection and Field Injection in Spring.

Summary

In this Spring Constructor Dependency Injection Example guide, you learnt how Constructor-based Dependency Injection works in a Spring Application. We also wrote executable code with Constructor Injection.

When a constructor is used to set instance variables of an object, it is called Constructor Injection. Before you dig deeper into using Spring Framework, it is important to understand the Difference Between Setter Injection vs Field Injection vs Constructor Injection.