Spring Field Dependency Injection Example
Learn how to write a Spring Field Injection example. 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.
More on Spring Dependency Injection:
- Spring Setter Dependency Injection Example
- Spring Constructor Dependency Injection Example
- Spring Dependency Injection – Field vs Setter vs Constructor Injection
- Spring Dependency Injection and Inversion of Control
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
Want to learn more about Spring Framework ?
Read this:
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.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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; } } |
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.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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; } } |
Run the Code
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | ' _| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2. 1.0 .RELEASE) 2019 - 02 - 05 06 : 34 : 14.956 INFO 69421 --- [ 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) 2019 - 02 - 05 06 : 34 : 14.957 INFO 69421 --- [ main] com.amitph.spring.dogs.Application : No active profile set, falling back to default profiles: default 2019 - 02 - 05 06 : 34 : 15.655 INFO 69421 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode. 2019 - 02 - 05 06 : 34 : 15.711 INFO 69421 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 50ms. Found 1 repository interfaces. 2019 - 02 - 05 06 : 34 : 16.013 INFO 69421 --- [ 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) 2019 - 02 - 05 06 : 34 : 16.318 INFO 69421 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019 - 02 - 05 06 : 34 : 16.335 INFO 69421 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019 - 02 - 05 06 : 34 : 16.335 INFO 69421 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/ 9.0 . 12 2019 - 02 - 05 06 : 34 : 16.342 INFO 69421 --- [ 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:.] 2019 - 02 - 05 06 : 34 : 16.429 INFO 69421 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019 - 02 - 05 06 : 34 : 16.429 INFO 69421 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1419 ms 2019 - 02 - 05 06 : 34 : 16.454 INFO 69421 --- [ main] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] 2019 - 02 - 05 06 : 34 : 16.457 INFO 69421 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] 2019 - 02 - 05 06 : 34 : 16.458 INFO 69421 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 2019 - 02 - 05 06 : 34 : 16.458 INFO 69421 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'formContentFilter' to: [/*] 2019 - 02 - 05 06 : 34 : 16.458 INFO 69421 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] 2019 - 02 - 05 06 : 34 : 16.581 INFO 69421 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool- 1 - Starting... 2019 - 02 - 05 06 : 34 : 16.702 INFO 69421 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool- 1 - Start completed. 2019 - 02 - 05 06 : 34 : 16.830 INFO 69421 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [ name: default ...] 2019 - 02 - 05 06 : 34 : 16.906 INFO 69421 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core { 5.3 . 7 .Final} 2019 - 02 - 05 06 : 34 : 16.907 INFO 69421 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found 2019 - 02 - 05 06 : 34 : 17.059 INFO 69421 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations { 5.0 . 4 .Final} 2019 - 02 - 05 06 : 34 : 17.188 INFO 69421 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect 2019 - 02 - 05 06 : 34 : 17.783 INFO 69421 --- [ 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 2019 - 02 - 05 06 : 34 : 18.208 INFO 69421 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019 - 02 - 05 06 : 34 : 18.244 WARN 69421 --- [ 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 2019 - 02 - 05 06 : 34 : 18.420 INFO 69421 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019 - 02 - 05 06 : 34 : 18.422 INFO 69421 --- [ main] com.amitph.spring.dogs.Application : Started Application in 3.878 seconds (JVM running for 4.57 ) |
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.
01 02 03 04 05 06 07 08 09 10 | @Component public class MyClass { @Autowired private DogsController controller; @Autowired private DogsService service; @Autowired private DogsDao dao; @Autowired private ApplicationProperties properties; ///// business methods } |
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.
Happy Coding !!
Published on Java Code Geeks with permission by Amit Phaltankar, partner at our JCG program. See the original article here: Spring Field Dependency Injection Example Opinions expressed by Java Code Geeks contributors are their own. |
hi Amit sorry is the question is plain. But why field DI is considered risky? thanks
Thanks for posting your question. Risky because it uses Reflection initialise fields. When we put ‘private’ instance variable we expect want to assure the fields be accessed via methods only. It is like, you are using a framework which doesn’t respect the access modifiers you put. Secondly with Field Injection, you class docs doesn’t provide any detail about how to initialise the fields. Consider if someone want’s to instantiate your class with a ‘new’ keyword. If there is are no setter no parameterised constructor. User will have to use reflection to set private fields on your class. I hope you… Read more »