This question already has answers here:
Setter DI vs. Constructor DI in Spring?
(9 answers)
Closed 5 years ago.
In a Pro Spring 3 Book,
Chapter 4 - Introduction IOC and DI in Spring - Page 59, In "Setter Injection vs. Constructor Injection" section, a paragraph says
Spring included, provide a mechanism for ensuring that all dependencies are defined when
you use Setter Injection, but by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner"
Could you explain with examples
A class that takes a required dependency as a constructor argument can only be instantiated if that argument is provided (you should have a guard clause to make sure the argument is not null) (or use a non-nullable type in Kotlin). A constructor therefore enforces the dependency requirement whether or not you're using Spring, making it container-agnostic.
If you use setter injection, the setter may or may not be called, so the instance may never be provided with its dependency. The only way to force the setter to be called is using #Required or #Autowired
, which is specific to Spring and is therefore not container-agnostic.
So to keep your code independent of Spring, use constructor arguments for injection. This applies to tests; you'll have an easier time instantiating and testing the class in a normal unit test, without needing to configure an application context or the complexity that comes along with setting up an integration test.
Update: Spring 4.3 will perform implicit injection in single-constructor scenarios, making your code more independent of Spring by potentially not requiring an #Autowired annotation at all.
(...) by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner
This mean that you can enforce requirements for all injected fields without using any container specific solution.
Setter injection example
With setter injection special spring annotation #Required is required.
#Required
Marks a method (typically a JavaBean setter method) as being 'required': that is, the setter method must be configured to be dependency-injected with a value.
Usage
import org.springframework.beans.factory.annotation.Required;
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class Foo {
private Bar bar;
#Inject
#Required
public void setBar(Bar bar) {
this.bar = bar;
}
}
Constructor injection example
All required fields are defined in constructor, pure Java solution.
Usage
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class Foo {
private Bar bar;
#Inject
public Foo(Bar bar) {
this.bar = bar;
}
}
Unit testing
This is especially useful in Unit Testing. Such kind of tests should be very simple and doesn't understand annotation like #Required, they generally not need a Spring for running simple unit test. When constructor is used, setup of this class for testing is much easier, there is no need to analyze how class under test is implemented.
To make it simple, let us say that we can use constructor based dependency injection for mandatory dependencies and setter based injection for optional dependencies. It is a rule of thumb!!
Let's say for example.
If you want to instantiate a class you always do it with its constructor. So if you are using constructor based injection, the only way to instantiate the class is through that constructor. If you pass the dependency through constructor it becomes evident that it is a mandatory dependency.
On the other hand, if you have a setter method in a POJO class, you may or may not set value for your class variable using that setter method. It is completely based on your need. i.e. it is optional. So if you pass the dependency through setter method of a class it implicitly means that it is an optional dependency. Hope this is clear!!
Constructor injection is used when the class cannot function without the dependent class.
Property injection is used when the class can function without the dependent class.
As a concrete example, consider a ServiceRepository which depends on IService to do its work. Since ServiceRepository cannot function usefully without IService, it makes sense to have it injected via the constructor.
The same ServiceRepository class may use a Logger to do tracing. The ILogger can be injected via Property injection.
Other common examples of Property injection are ICache (another aspect in AOP terminology) or IBaseProperty (a property in the base class).
By using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner
We need the assurance from the IoC container that, before using any bean, the injection of necessary beans must be done.
In setter injection strategy, we trust the IoC container that it will first create the bean first but will do the injection right before using the bean using the setter methods. And the injection is done according to your configuration. If you somehow misses to specify any beans to inject in the configuration, the injection will not be done for those beans and your dependent bean will not function accordingly when it will be in use!
But in constructor injection strategy, container imposes (or must impose) to provide the dependencies properly while constructing the bean. This was addressed as " container-agnostic manner", as we are required to provide dependencies while creating the bean, thus making the visibility of dependency, independent of any IoC container.
Edit:
Q1: And how to prevent container from creating bean by constructor with null values instead of missing beans?
You have no option to really miss any <constructor-arg> (in case of Spring), because you are imposed by IoC container to provide all the constructor arguments needed to match a provided constructor for creating the bean. If you provide null in your <constructor-arg> intentionally. Then there is nothing IoC container can do or need to do with it!
This example may help:
Controller class:
#RestController
#RequestMapping("/abc/dev")
#Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class MyController {
//Setter Injection
#Resource(name="configBlack")
public void setColor(Color c) {
System.out.println("Injecting setter");
this.blackColor = c;
}
public Color getColor() {
return this.blackColor;
}
public MyController() {
super();
}
Color nred;
Color nblack;
//Constructor injection
#Autowired
public MyController(#Qualifier("constBlack")Color b, #Qualifier("constRed")Color r) {
this.nred = r;
this.nblack = b;
}
private Color blackColor;
//Field injection
#Autowired
private Color black;
//Field injection
#Resource(name="configRed")
private Color red;
#RequestMapping(value = "/customers", produces = { "application/text" }, method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.CREATED)
public String createCustomer() {
System.out.println("Field injection red: " + red.getName());
System.out.println("Field injection: " + black.getName());
System.out.println("Setter injection black: " + blackColor.getName());
System.out.println("Constructor inject nred: " + nred.getName());
System.out.println("Constructor inject nblack: " + nblack.getName());
MyController mc = new MyController();
mc.setColor(new Red("No injection red"));
System.out.println("No injection : " + mc.getColor().getName());
return "Hello";
}
}
Interface Color:
public interface Color {
public String getName();
}
Class Red:
#Component
public class Red implements Color{
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Red(String name) {
System.out.println("Red color: "+ name);
this.name = name;
}
public Red() {
System.out.println("Red color default constructor");
}
}
Class Black:
#Component
public class Black implements Color{
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Black(String name) {
System.out.println("Black color: "+ name);
this.name = name;
}
public Black() {
System.out.println("Black color default constructor");
}
}
Config class for creating Beans:
#Configuration
public class Config {
#Bean(name = "configRed")
public Red getRedInstance() {
Red red = new Red();
red.setName("Config red");
return red;
}
#Bean(name = "configBlack")
public Black getBlackInstance() {
Black black = new Black();
black.setName("config Black");
return black;
}
#Bean(name = "constRed")
public Red getConstRedInstance() {
Red red = new Red();
red.setName("Config const red");
return red;
}
#Bean(name = "constBlack")
public Black getConstBlackInstance() {
Black black = new Black();
black.setName("config const Black");
return black;
}
}
BootApplication (main class):
#SpringBootApplication
#ComponentScan(basePackages = {"com"})
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
Run Application and hit URL:
GET 127.0.0.1:8080/abc/dev/customers/
Output:
Injecting setter
Field injection red: Config red
Field injection: null
Setter injection black: config Black
Constructor inject nred: Config const red
Constructor inject nblack: config const Black
Red color: No injection red
Injecting setter
No injection : No injection red
With examples? Here's a simple one:
public class TwoInjectionStyles {
private Foo foo;
// Constructor injection
public TwoInjectionStyles(Foo f) {
this.foo = f;
}
// Setting injection
public void setFoo(Foo f) { this.foo = f; }
}
Personally, I prefer constructor injection when I can.
In both cases, the bean factory instantiates the TwoInjectionStyles and Foo instances and gives the former its Foo dependency.
Related
Let's suppose I have a Wrapper with generic type:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Wrapper<T> {
private final Class<T> wrappedClass;
public Wrapper(Class<T> wrappedClass) {
this.wrappedClass = wrappedClass;
}
}
And I want to use this Wrapper with many classes (for example > 100). Is it possible to make Spring create singleton of wrapper for each generic type and pass generic class as parameter to constructor? For example, Spring must always inject the same instance of Wrapper<Foo>. If it is possible, please give example with java code configuration, but not with xml.
If I understood correctly you want to add beans of wrapper dynamically based on some criteria that some beans (like Foo / Bar) adhere to and some don't.
This is a kind of advanced stuff in spring, but in a nutshell you will have to implement a Bean Factory Post Processor that will be called automatically by spring during the startup.
This is a point where you could analyze the beans by iterating over all the "accessible" beans (like Foo / Bar and others) and for beans that should be wrapped you will create a bean definition of the wrapper, despite the fact that the wrapper itself is not a bean.
I've created a simple example to illustrate this. In my sample project I've put everything under package "wrappers":
#Wrappable
public class Foo {
}
#Wrappable
public class Bar {
}
public class ShouldNotBeWrapped {
}
Note that I've put an annotation #Wrappable - a custom annotation that will serve as a "differentiator" of what should be wrapped and what not. The processing of the annotation will be done in Bean Factory Post Processor.
The annotation is nothing special really, it should be acessible in runtime (spring is a runtime framework and be put on classes):
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Wrappable {
}
The java config will add Foo, Bar, ShouldNotBeWrapped as beans and also Bean Factory Post Processor that I'll describe below:
#Configuration
public class WrappersJavaConfig {
#Bean
public Foo foo () {
return new Foo();
}
#Bean
public Bar bar () {
return new Bar();
}
#Bean
public ShouldNotBeWrapped shouldNotBeWrapped () {
return new ShouldNotBeWrapped();
}
#Bean
public WrappersEnrichmentBFPP wrappersEnrichmentBFPP () {
return new WrappersEnrichmentBFPP();
}
}
The Wrapper class itself for the sake of example has toString but it doesn't differ much from your wrapper presented in the question:
public class Wrapper<T> {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
#Override
public String toString() {
return "Wrapper for" + wrapped;
}
}
And the Main class will list all the loaded beans and get their classes + call toString so that we could see that the wrappers are defined correctly:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(WrappersJavaConfig.class);
String[] names = ctx.getBeanDefinitionNames();
for(String name : names) {
Object bean = ctx.getBean(name);
if(bean.getClass().getPackage().getName().startsWith("wrappers")) {
System.out.println(ctx.getBean(name).getClass() + " ==> " + ctx.getBean(name));
}
}
}
}
Sidenote, the "if" condition in the main method is because I don't want to print the beans that spring loads by itself (infra stuff, etc) - only my beans which all reside in package "wrappers" as I've mentioned above.
Now the BeanFactoryPostProcessor - is a regular bean in a sense that it gets registered in the java config and it looks like this (your implementation might be different but the idea is the same):
public class WrappersEnrichmentBFPP implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] bddNames = beanFactory.getBeanDefinitionNames();
for(String bddName : bddNames) {
Object bean = beanFactory.getBean(bddName);
if(bean.getClass().isAnnotationPresent(Wrappable.class)) {
BeanDefinition wrappedBdd = BeanDefinitionBuilder.genericBeanDefinition(Wrapper.class)
.addConstructorArgReference(bddName)
.getBeanDefinition();
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("wrapperFor" + bddName, wrappedBdd);
}
}
}
}
So I'm getting all the beans one by one in for-each loop, then I'm asking whether the bean has an annotation "wrappable" on it in the if condition. If it has - it must be wrapped.
In this case I create an "artificial" bean definition for Wrapper and add a constuctor that will reference my bean that should be wrapped.
Then I register the bean definition by adding it to the application context.
Run the code above and you'll see the output similar to mine:
class wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d ==> wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d#1283bb96
class wrappers.Foo ==> wrappers.Foo#74f0ea28
class wrappers.Bar ==> wrappers.Bar#f6efaab
class wrappers.ShouldNotBeWrapped ==> wrappers.ShouldNotBeWrapped#3c19aaa5
class wrappers.WrappersEnrichmentBFPP ==> wrappers.WrappersEnrichmentBFPP#3349e9bb
class wrappers.Wrapper ==> Wrapper forwrappers.Foo#74f0ea28
class wrappers.Wrapper ==> Wrapper forwrappers.Bar#f6efaab
As you see, two last lines are lines that correspond to the wrapper beans created for the same instances of Foo and Bar but nothing was created for the ShouldNotBeWrapped bean
The APIs used are somewhat obscure and look outdated, but again its pretty advanced stuff and works at the level of spring container infra itself. Having said that, there are a lot of tutorials about BeanFactoryPostProcessor-s.
Since Using BFPPs is not a usual task, and although I've provided the solution, I don't see any real usage of it, wrappers can't be used "instead" of Foo or Bar classes, do not have their APIs, etc. Maybe you could explain why do you need wrappers over some beans. Usually people use Aspects/BeanPostProcessors (not BFPP but BPP) to wrap the class into dynamic proxy (cglib / java.lang.Proxy) and add an additional behavior, stuff like #Transactional, cache handling and so forth is implemented in spring with BeanPostProcessors, so consider checking this direction as well.
It is possible and in fact a feature in spring.
Spring can inject your dependency with the correct generic type.The following example is from spring documentation.
Suppose you have an interface
public interface Store<T>{...}
and two beans. One implements Store,one implemenets Store.
#Configuration
public class MyConfiguration {
#Bean
public StringStore stringStore() {
return new StringStore();
}
#Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
You can declare the type with the correct type parameter and spring will inject the right bean for you.
#Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
#Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
I have a demo class FooComponent which is autowired in FooService and accessed in its constructor.
FooComponent.class:
#Component("fooComponent")
public class FooComponent {
public String format() {
return "foo";
}
}
FooService.class:
#Component
public class FooService {
#Autowired
private FooComponent fooComponent;
public FooService() {
System.out.println("in foo service const=" + this.fooComponent);
}
String doTatti() {
return fooComponent.format();
}
}
MainApplication:
#SpringBootApplication
public class InterviewApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(InterviewApplication.class, args);
System.out.println(ctx.getBean(FooService.class).doTatti());
}
}
In this tutorial, author says In the above example, Spring looks for and injects fooFormatter when FooService is created. In my case, fooFormatter is fooComponent.
But everytime, in the constructor my autowired property is null. My assumption is that it is because FoOService has not completely initialized? Is this correct?
If my assumption is correct, then why does below code work?
#Autowired
public FooService(FooComponent fooComponent) {
System.out.println("in foo service const=" + fooComponent);
}
I know this is very basic and stupid question, but I need help in understanding it.
UPDATE:
One last query, is there a way to Autowire my FooService instance in MainApplication, instead of getting it from ApplicationContext?
Thank you in advance.
In Spring, a bean is instantiated before its properties are injected. That is:
Instantiate the bean first
Inject the properties
This is because spring uses setter methods of the instantiated bean in order to inject properties.
This is the reason you are getting NullPointerException.
Preferable and recommended option is to use constructor injection, not a property or setter injection. In additional, one of the ways to resolve this is to create constructor with parameter as you did.
The whole explanation you can check here:
https://dzone.com/articles/spring-accessing-injected
EDIT:
Beans should be managed by the container. If we want to use one of them, we should rely on dependency injection rather than a direct call to ApplicationContext.getBean().
See this post: Why is Spring's ApplicationContext.getBean considered bad?
You need to use constructor injection instead of setter injection.
one of the drawbacks of setter injection is that it does not ensures dependency Injection. You can not guarantee that certain dependency is injected or not, which means you may have an object with incomplete dependency. On the other hand, constructor Injection does not allow you to construct an object until your dependencies are ready.
for your first question, u r right. Also when u need an object in the constructor you have to use the constructor injection and not property injection with #autowired;
for your second one, u can use the #Autowired prop in the main, but usually in this case is better to do your logic in the override of the commandLineRunner interface as follow :
#Autowired
private FooService foo;
public static void main(String[] args) {
SpringApplication.run(InterviewApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
foo.doTatti();
...
}
This question already has answers here:
Setter DI vs. Constructor DI in Spring?
(9 answers)
Closed 5 years ago.
In a Pro Spring 3 Book,
Chapter 4 - Introduction IOC and DI in Spring - Page 59, In "Setter Injection vs. Constructor Injection" section, a paragraph says
Spring included, provide a mechanism for ensuring that all dependencies are defined when
you use Setter Injection, but by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner"
Could you explain with examples
A class that takes a required dependency as a constructor argument can only be instantiated if that argument is provided (you should have a guard clause to make sure the argument is not null) (or use a non-nullable type in Kotlin). A constructor therefore enforces the dependency requirement whether or not you're using Spring, making it container-agnostic.
If you use setter injection, the setter may or may not be called, so the instance may never be provided with its dependency. The only way to force the setter to be called is using #Required or #Autowired
, which is specific to Spring and is therefore not container-agnostic.
So to keep your code independent of Spring, use constructor arguments for injection. This applies to tests; you'll have an easier time instantiating and testing the class in a normal unit test, without needing to configure an application context or the complexity that comes along with setting up an integration test.
Update: Spring 4.3 will perform implicit injection in single-constructor scenarios, making your code more independent of Spring by potentially not requiring an #Autowired annotation at all.
(...) by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner
This mean that you can enforce requirements for all injected fields without using any container specific solution.
Setter injection example
With setter injection special spring annotation #Required is required.
#Required
Marks a method (typically a JavaBean setter method) as being 'required': that is, the setter method must be configured to be dependency-injected with a value.
Usage
import org.springframework.beans.factory.annotation.Required;
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class Foo {
private Bar bar;
#Inject
#Required
public void setBar(Bar bar) {
this.bar = bar;
}
}
Constructor injection example
All required fields are defined in constructor, pure Java solution.
Usage
import javax.inject.Inject;
import javax.inject.Named;
#Named
public class Foo {
private Bar bar;
#Inject
public Foo(Bar bar) {
this.bar = bar;
}
}
Unit testing
This is especially useful in Unit Testing. Such kind of tests should be very simple and doesn't understand annotation like #Required, they generally not need a Spring for running simple unit test. When constructor is used, setup of this class for testing is much easier, there is no need to analyze how class under test is implemented.
To make it simple, let us say that we can use constructor based dependency injection for mandatory dependencies and setter based injection for optional dependencies. It is a rule of thumb!!
Let's say for example.
If you want to instantiate a class you always do it with its constructor. So if you are using constructor based injection, the only way to instantiate the class is through that constructor. If you pass the dependency through constructor it becomes evident that it is a mandatory dependency.
On the other hand, if you have a setter method in a POJO class, you may or may not set value for your class variable using that setter method. It is completely based on your need. i.e. it is optional. So if you pass the dependency through setter method of a class it implicitly means that it is an optional dependency. Hope this is clear!!
Constructor injection is used when the class cannot function without the dependent class.
Property injection is used when the class can function without the dependent class.
As a concrete example, consider a ServiceRepository which depends on IService to do its work. Since ServiceRepository cannot function usefully without IService, it makes sense to have it injected via the constructor.
The same ServiceRepository class may use a Logger to do tracing. The ILogger can be injected via Property injection.
Other common examples of Property injection are ICache (another aspect in AOP terminology) or IBaseProperty (a property in the base class).
By using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner
We need the assurance from the IoC container that, before using any bean, the injection of necessary beans must be done.
In setter injection strategy, we trust the IoC container that it will first create the bean first but will do the injection right before using the bean using the setter methods. And the injection is done according to your configuration. If you somehow misses to specify any beans to inject in the configuration, the injection will not be done for those beans and your dependent bean will not function accordingly when it will be in use!
But in constructor injection strategy, container imposes (or must impose) to provide the dependencies properly while constructing the bean. This was addressed as " container-agnostic manner", as we are required to provide dependencies while creating the bean, thus making the visibility of dependency, independent of any IoC container.
Edit:
Q1: And how to prevent container from creating bean by constructor with null values instead of missing beans?
You have no option to really miss any <constructor-arg> (in case of Spring), because you are imposed by IoC container to provide all the constructor arguments needed to match a provided constructor for creating the bean. If you provide null in your <constructor-arg> intentionally. Then there is nothing IoC container can do or need to do with it!
This example may help:
Controller class:
#RestController
#RequestMapping("/abc/dev")
#Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class MyController {
//Setter Injection
#Resource(name="configBlack")
public void setColor(Color c) {
System.out.println("Injecting setter");
this.blackColor = c;
}
public Color getColor() {
return this.blackColor;
}
public MyController() {
super();
}
Color nred;
Color nblack;
//Constructor injection
#Autowired
public MyController(#Qualifier("constBlack")Color b, #Qualifier("constRed")Color r) {
this.nred = r;
this.nblack = b;
}
private Color blackColor;
//Field injection
#Autowired
private Color black;
//Field injection
#Resource(name="configRed")
private Color red;
#RequestMapping(value = "/customers", produces = { "application/text" }, method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.CREATED)
public String createCustomer() {
System.out.println("Field injection red: " + red.getName());
System.out.println("Field injection: " + black.getName());
System.out.println("Setter injection black: " + blackColor.getName());
System.out.println("Constructor inject nred: " + nred.getName());
System.out.println("Constructor inject nblack: " + nblack.getName());
MyController mc = new MyController();
mc.setColor(new Red("No injection red"));
System.out.println("No injection : " + mc.getColor().getName());
return "Hello";
}
}
Interface Color:
public interface Color {
public String getName();
}
Class Red:
#Component
public class Red implements Color{
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Red(String name) {
System.out.println("Red color: "+ name);
this.name = name;
}
public Red() {
System.out.println("Red color default constructor");
}
}
Class Black:
#Component
public class Black implements Color{
private String name;
#Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Black(String name) {
System.out.println("Black color: "+ name);
this.name = name;
}
public Black() {
System.out.println("Black color default constructor");
}
}
Config class for creating Beans:
#Configuration
public class Config {
#Bean(name = "configRed")
public Red getRedInstance() {
Red red = new Red();
red.setName("Config red");
return red;
}
#Bean(name = "configBlack")
public Black getBlackInstance() {
Black black = new Black();
black.setName("config Black");
return black;
}
#Bean(name = "constRed")
public Red getConstRedInstance() {
Red red = new Red();
red.setName("Config const red");
return red;
}
#Bean(name = "constBlack")
public Black getConstBlackInstance() {
Black black = new Black();
black.setName("config const Black");
return black;
}
}
BootApplication (main class):
#SpringBootApplication
#ComponentScan(basePackages = {"com"})
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
Run Application and hit URL:
GET 127.0.0.1:8080/abc/dev/customers/
Output:
Injecting setter
Field injection red: Config red
Field injection: null
Setter injection black: config Black
Constructor inject nred: Config const red
Constructor inject nblack: config const Black
Red color: No injection red
Injecting setter
No injection : No injection red
With examples? Here's a simple one:
public class TwoInjectionStyles {
private Foo foo;
// Constructor injection
public TwoInjectionStyles(Foo f) {
this.foo = f;
}
// Setting injection
public void setFoo(Foo f) { this.foo = f; }
}
Personally, I prefer constructor injection when I can.
In both cases, the bean factory instantiates the TwoInjectionStyles and Foo instances and gives the former its Foo dependency.
I am a complete Spring beginner and I am trying to get basic configuration with Spring Boot working. I would like to use constructor injection wherever possible. However, Spring is throwing exceptions that I do not understand. I've shortened the problematic code for easier reading:
My config YAML file (I have snake yaml on the classpath):
database:
inactive_timeout: 100
active_jdbc_connections:
# this is a list with one property in each element
- name: foo
- name: bar
- name: baz
- name: qux
The application code:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoApplication {
private final DBProperties dbProperties;
DBProperties getDbProperties() {
return dbProperties;
}
public DemoApplication(DBProperties dbProperties) {
this.dbProperties = dbProperties;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
And the class that Spring is failing to wire properly:
package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
#ConfigurationProperties(prefix = "database")
#Component
public class DBProperties {
private final List<ConnectionProperties> activeJdbcConnections;
private int inactiveTimeout;
// ERROR: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'int' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
public DBProperties(List<ConnectionProperties> activeJdbcConnections, int inactiveTimeout) {
this.activeJdbcConnections = activeJdbcConnections;
this.inactiveTimeout = inactiveTimeout;
}
public List<ConnectionProperties> getActiveJdbcConnections() {
return activeJdbcConnections;
}
public int getInactiveTimeout() {
return inactiveTimeout;
}
#Component
public static class ConnectionProperties {
private String name;
// ERROR: Parameter 0 of constructor in com.example.demo.DBProperties$ConnectionProperties required a bean of type 'java.lang.String' that could not be found.
public ConnectionProperties(String name){
this.name = name;
}
public String getName() {
return name;
}
}
}
There are two separate errors. First, in the DBProperties constructor Spring is not able to wire the integer inactiveTimeout, even though it has no trouble wiring the parameter activeJdbcConnections. This can be solved using the #Value parameter, but this is undesirable because #Value does not recognize the prefix specified by #ConfigurationParameters, and so the prefix must be repeated for each #Value annotation.
Second, Spring cannot wire the name parameter of ConnectionProperties. Spring is able to work with a setter if it is added, but as stated above I want to work with constructor injection. As the name of the parameter matches the property I want wired, I do not understand the problem here. As a side note, I was unable to solve this with an #Value annotation, as I do not know the syntax for specifying a property from the current list element.
How can I get Spring to properly instantiate my configuration classes using constructor injection?
There are a few issues with your approach I think. Firstly you can't define beans of type int and String (even if you did try to define them somewhere) so the name and inactiveTimeout will never be available as beans to autowire through constructor injection.
Secondly, #Components when scanned are Spring singleton beans by default which means that there is only one instance of them per Spring context. It doesn't really then make sense for ConnectionProperties to be a component if you're passing it in a list for the DBProperties constructor since there can only be one instatiated ConnectionProperties so it would be a bit of a short list!
If you want DBProperties to be a bean with some parameters provided in its constructor then you probably want to define it as a #Bean directly and call the constructor yourself. Spring can't work out what parameters you want to put in there! Something like:
#Bean
public DBProperties dbProperties() {
...
return new DBProperties(myArray, myNumber);
}
Then this DBProperties bean will be available to be Constructor injected anywhere else in your Spring boot application.
I'm new to Java Spring and trying to use Java configuration and inject a dependency into a class constructor. I want to use constructor injection because the class methods require the dependency. It isn't working for me.
Use case: Create a JSON string from a Java object and validate it before returning.
Class: FakeJsonBuilder
Dependency: JsonValidator
Main class: Per Spring documentation the #SpringBootApplication annotation is a convenience annotation that adds #Configuration, #EnableAutoConfiguration and #ComponentScan so I should be good to go as far as dependency injection is concerned.
#SpringBootApplication
public class MySpringApplication {
public static void main(String[] args){
// Register the class we use for Java based configuration
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
context.register(ApplicationConfiguration.class);
context.refresh();
SpringApplication.run(MySpringApplication .class, args);
}
}
Java configuration class:
#Configuration
public class ApplicationConfiguration {
#Bean
public JsonValidator jsonValidator(){
return new JsonValidatorImpl();
}
#Bean
public JsonBuilder(){
return new FakeJsonBuilder();
}
}
FakeJsonBuilder class:
public class FakeJsonBuilder implements JsonBuilder{
private static Log logger = LogFactory.getLog(FakeJsonBuilder.class);
private static JsonValidator jsonValidator;
// I need an empty constructor for the ApplicationConfiguration setup to work.
public MlrModelJsonBuilder(){};
#Autowired
public FakeJsonBuilder (JsonValidator jsonValidator){
this.jsonValidator = jsonValidator;
boolean validatorInjected = (jsonValidator != null);
logger.info("Validator injected: " + validatorInjected);
}
.......... More methods
The jsonValidator dependency is not being injected, i.e. the log message is Validator injected: false
Quoting Martin: Fowler http://martinfowler.com/articles/injection.html
"My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations."
I come from a .NET background and use Ninject to inject my dependencies into the class constructor for the reasons Fowler gives. I quoted Fowler because of his credibility but you will find many sources providing the same argument, i.e. if the class methods require the dependency then it should be injected into the constructor. So here's how I figured how to do it with Java Spring (I revert to my C# syntax - forgive the transgression):
The configuration class
#Configuration
public class ApplicationConfiguration {
#Bean
public IJsonValidator jsonValidator(){
return new JsonValidator();
}
#Bean
public IJsonBuilder jsonBuilder(){
return new JsonBuilder(jsonValidator());
}
}
The class into which we inject the dependency
public class JsonBuilder implements IJsonBuilder {
private static IJsonValidator _jsonValidator;
// #Autowired // not needed per Sotirios. tested and verified
public JsonBuilder(IJsonValidator jsonValidator) {
_jsonValidator = jsonValidator;
}
public String getFoobar() {
// Returns false. jsonValidator was injected
boolean foo = (_jsonValidator == null);
return "Validator was injected: " + foo;
}
... more methods