Spring Setter Dependency Injection Example

Learn how to write Spring Setter Dependency Injection Example. The Setter Injection is a type of Spring Dependency Injection.

Overview

Spring supports Field Injection, Setter Injection as well as Constructor injection to inject dependencies in a Spring managed bean. Scope of this tutorial is limited to Setter Injections.

What is Spring Setter Injection?

Spring Setter Injection is nothing but injecting the Bean Dependencies using the Setter methods on an Object. Unlike Spring Constructor Injection, in Setter Injection, the object is created first and then the dependency is injected.

Consider, we have a DogsService, which is a Spring based REST Service.

We will write a DogsController, DogsService, and a DogsDao. This is a dummy service which does nothing. Intention here is to see how the Spring Dependency Injection works with Setter methods.

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

Want to learn more about Spring Framework ?
Read this:

DogsDao.java

There are no fields hence no dependency. We have added a no-argument constructor with a print message.

package com.amitph.spring.dogs.dao;

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)

DogsService.java

The DogsService depends on DogsDao. In the class below the setter method is annotated with @Autowired. To see how the Setter Injection works we have added a print statement in the setter method. Along with a setter method, we have also added a no-argument constructor and a parameterised constructor with respective print messages.

package com.amitph.spring.dogs.service;

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();
    }

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

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

DogsController.java

The DogsController depends upon DogsService. The setter is annotated with @Autowired and has a print statement. Along with the setter method, we have also added a no-argument and a parameterised constructor along with respective print messages.

package com.amitph.spring.dogs.web;

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();
    }

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

Application Startup

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.0.RELEASE)

INFO [main] com.amitph.spring.dogs.Application       : Starting Application on Amitsofficemac.gateway with PID 68545 (/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 48ms. Found 1 repository interfaces.
INFO [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$4a5366ed] 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 1205 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 no-arg constructor called
DogsService setter called
DogsController no-arg constructor called
DogsController setter 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.138 seconds (JVM running for 3.647)Code language: plaintext (plaintext)

What happened here is the Spring first tried to instantiate DogsController and found a dependency over DogsService. Hence, it went to instantiate DogsService, which in-turn has a dependency over DogsDao. Hence the DogsDao is the first to get instantiated, then DogsService and finally the DogsController.

Let’s see what happened in detail.

  • Line #36: No-argument constructor of DogsDao is called.
  • Line #37: No-argument constructor of DogsService is called. Note: the parameterised constructor never got called.
  • Line #38: Setter of DogsService is called. Where instance of DogsDao (created at line #36) is injected.
  • Line #39: No-argument constructor of DogsController is called.
  • Line #40: Setter of DogsController is called. The DogsService instance (created in line #37) is injected.

The log shows that the objects get created first and then the dependency is injected. Very similar to Setter Injection Spring also supports Field Injection. The Spring Field Injection based on setting the fields directly using Java Reflections API.

Summary

You learnt How to write a Setter Injection in a Spring Application. In case of Setter Injection, the setter methods are annotated with @Autowired. Spring will first use the no-argument constructor to instantiate the bean and then call setter methods to inject the dependencies.

In the coming tutorial we will see Spring Constructor Injection Example.