Spring Field Dependency Injection Example

Learn how to write a Spring Field Injection example.

Overview

The Field Injection is a type of Spring Frameworks Dependency Injection. In this tutorial we will write couple of classes and see hot the Field Injection Works.

Field Based Dependency Injection

In this type of Dependency Injection, Spring assigns the dependencies directly to the fields. It is different than Constructor Injection or Setter based Dependency Injection.

The interesting thing to understand is, Spring injects the dependencies, even if the field is private. Spring uses Java Reflections to do so. Hence it is called unsafe by many of the experts.

The Field Injection is probably the simplest (yet risky) form of Dependency Injection. To understand it better we will assume we have a running Spring Boot Service. It is a dummy service for the purpose of understanding Field Injection.

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

Let’s write our DogsService class first

The Dogs Service

This class has a dependency over DogsDao. As annotated the reference variable with @Autowired. There is a setter and two constructors with respective print messages.

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 {
    @Autowired
    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");
    }

    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 dependency over the DogsService. Similar to the service class the annotation @Autowired is added to the reference variable. There are setter and constructors with print messages.

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 {
    @Autowired
    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");
    }

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

Run the Code

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

INFO [main] com.amitph.spring.dogs.Application       : Starting Application on Amits-office-mac.local with PID 69421 (/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 50ms. Found 1 repository interfaces.
INFO [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$1cc57cd7] 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 1419 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
DogsController no-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.878 seconds (JVM running for 4.57)Code language: plaintext (plaintext)

All three no-argument controllers called in sequence. No setter or parameterised constructors were called. One more thing to notice is the the fields, which were marked @Autowired are private.

Spring can set private fields

Spring uses reflection to set the private fields on our object. This sounds useful and on the other hand it is not safe. The field injection, its safety and usefulness it always debated. Spring Doesn’t respect an Objects access rules. Now, some people may support this or say spring IoC container manages all the objects and should get supreme control over the objects.

@Component
public class MyClass {

    @Autowired private DogsController controller;
    @Autowired private DogsService service;
    @Autowired private DogsDao dao;
    @Autowired private ApplicationProperties properties;

///// business methods
}Code language: Java (java)

As a developer, I always love using Field Injection as it is really simple and more readable. You can actually avoid writing setter methods or constructors and concentrate on the business methods.

Summary

You learnt the Field Injection is a type of Spring Dependency Injection, and wrote couple of classes to see it working. The Field injection is simple and makes a class more readable. However, many people hate it and avoid using it because of its safety concerns.

In the coming sections we will see a detailed difference between all the three of Setter Injection, Field Injection, and Constructor Injection.