So since I've been using Spring, if I were to write a service that had dependencies I would do the following:
#Component
public class SomeService {
#Autowired private SomeOtherService someOtherService;
}
I have now run across code that uses another convention to achieve the same goal
#Component
public class SomeService {
private final SomeOtherService someOtherService;
#Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Both of these methods will work, I understand that. But is there some advantage to using option B? To me, it creates more code in the class and unit test. (Having to write constructor and not being able to use #InjectMocks)
Is there something I'm missing? Is there anything else the autowired constructor does besides add code to the unit tests? Is this a more preferred way to do dependency injection?
Yes, option B (which is called constructor injection) is actually recommended over field injection, and has several advantages:
the dependencies are clearly identified. There is no way to forget one when testing, or instantiating the object in any other circumstance (like creating the bean instance explicitly in a config class)
the dependencies can be final, which helps with robustness and thread-safety
you don't need reflection to set the dependencies. InjectMocks is still usable, but not necessary. You can just create mocks by yourself and inject them by simply calling the constructor
See this blog post for a more detailed article, by one of the Spring contributors, Olivier Gierke.
I will explain you in simple words:
In Option(A), you are allowing anyone (in different class outside/inside the Spring container) to create an instance using default constructor (like new SomeService()), which is NOT good as you need SomeOtherService object (as a dependency) for your SomeService.
Is there anything else the autowired constructor does besides add code
to the unit tests? Is this a more preferred way to do dependency
injection?
Option(B) is preferred approach as it does NOT allow to create SomeService object without actually resolving the SomeOtherService dependency.
Please note, that since Spring 4.3 you don't even need an #Autowired on your constructor, so you can write your code in Java style rather than tying to Spring's annotations.
Your snippet would look like that:
#Component
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Good to know
If there is only one constructor call, there is no need to include an #Autowired annotation. Then you can use something like this:
#RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
... example of Spring Data Repository injection.
Actually, In my experience, The second option is better. Without the need for #Autowired. In fact, it is wiser to create code that is not too tightly coupled with the framework (as good as Spring is). You want code that tries as much as possible to adopt a deferred decision-making approach. That is as much pojo as possible, so much such that the framework can be swapped out easily.
So I would advise you create a separate Config file and define your bean there, like this:
In SomeService.java file:
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
In ServiceConfig.java file:
#Config
public class ServiceConfig {
#Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
In fact, if you want to get deeply technical about it, there are thread safety questions (among other things) that arise with the use of Field Injection (#Autowired), depending on the size of the project obviously. Check this out to learn more on the advantages and disadvantages of Autowiring. Actually, the pivotal guys actually recommend that you use Constructor injection instead of Field Injection
I hope I won't be downgraded for expressing my opinion, but for me option A better reflects the power of Spring dependency injection, while in the option B you are coupling your class with your dependency, in fact you cannot instantiate an object without passing its dependencies from the constructor. Dependency Injection have been invented for avoid that by implementing Inversion of Control,so for me option B doesn't have any sense.
Autowired constructors provides a hook to add custom code before registering it in the spring container. Suppose SomeService class extends another class named SuperSomeService and it has some constructor which takes a name as its argument. In this case, Autowired constructor works fine. Also, if you have some other members to be initialized, you can do it in the constructor before returning the instance to spring container.
public class SuperSomeService {
private String name;
public SuperSomeService(String name) {
this.name = name;
}
}
#Component
public class SomeService extends SuperSomeService {
private final SomeOtherService someOtherService;
private Map<String, String> props = null;
#Autowired
public SomeService(SomeOtherService someOtherService){
SuperSomeService("SomeService")
this.someOtherService = someOtherService;
props = loadMap();
}
}
I prefer construction injection, just because I can mark my dependency as final which is not possible while injecting properties using property injection.
your dependencies should be final i.e not modified by program.
There are few cases when #Autowired is preferable.
One of them is circular dependency. Imagine the following scenario:
#Service
public class EmployeeService {
private final DepartmentService departmentService;
public EmployeeService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
}
and
#Service
public class DepartmentService {
private final EmployeeService employeeService;
public DepartmentService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Then Spring Bean Factory will throw circular dependency exception. This won't happen if you use #Autowired annotation in both beans. And this is understandable: the constructor injection happens at very early stage of Spring Bean initialization, in createBeanInstance method of Bean Factory, while #Autowired-based injection happens way later, on post processing stage and is done by AutowiredAnnotationBeanPostProcessor.
Circular dependency is quite common in complex Spring Context application, and it needs not to be just two beans referring one another, it could a complex chain of several beans.
Another use case, where #Autowired is very helpful, is self-injection.
#Service
public class EmployeeService {
#Autowired
private EmployeeService self;
}
This might be needed to invoke an advised method from within the same bean. Self-injection is also discussed here and here.
There is a way to inject the dependencies through constructor using #RequeiredArgsContructor annotation from Lombok
#RequiredArgsConstructor
#Service
class A {
private final B b // needs to be declared final to be injected
}
In this way you don't need to specify a constructor
For example, have a class like as follows.
First XService service in class A is not null but second XService service in AmountValidator is null.I get NullPointerException I try to create bean new it works and then I get same exception when call AmountValidateService outsideRestService in XService.
How can I use XService everywhere that I use #Autowired annotation.
My main class:
#Service
class A extends AbstractA implements IA {
#Autowired
XService service; //first autowired definition. code go to check() method. service not null now.
public doSometing(){
validator.check();
service.methodA();
super.AbstractMethod();
}
}
Validator class used in class A :
class Validator<T> implements IValidator<T> {
public void check(){
rule.check(); // rule have a implements IValidator eg: amountValidator, dateValidator class
}
}
AmountValidator added to rule in class Validator.
#Component
class AmountValidator implements IValidator<T>{
#Autowired
XService service; // code comes here service is null. same service class mentioned above class A.
#Override
public void check(){
service.validateAmount(); // nullPointerException.
}
}
My main Service
#Component
class XService {
#Autowired
AmountValidateService outsideRestService;
public validateAmount(){
outsideRestService.validate(); // nullPointer when create XService with the `New` keyword
}
}
You have an error cause you are trying to create components/beans/services yourself. As i mentioned in comment when you create components yourself it - #Autowired doesn't work - thats you've got NPE
All classes annotated with #Component, #Service are considered special classes which are instantiated by Spring automatically via DI, instantiating them with new defeats the purpose of DI.
These special classes are named Spring Beans.
Every time the application starts, the framework instances all Spring Beans, and all #Autowired fields are injected by Spring automatically. But the Spring Beans must be defined somewhere in the class path. Else you will receive a NoSuchBeanDefinitionException
As an attempt to answer the question, since I don't have a stack trace nor all the Spring Bean definitions:
When you instantiate XService using new XService() your new instance will not actually initialize the field AmountValidateService outsideRestService, effectively leaving it as null.
You may set the field yourself but as I mentioned earlier, it defeats the purpose of DI
Your question is not complex, it is incomplete.
#Component
public class BeanA {
...
}
#Component
public class BeanB {
#Autowired
BeanA beanA;
public BeanB() {
// Use beanA
beanA.method();
}
}
Can we assume BeanA is created and initialized before BeanB constructor is called? (I know we can pass BeanA as constructor arg to BeanB, this is more of curiosity question to understand spring/java initialisation sequence)
Take a look at http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers
Setting properties on bean would happen after it is constructed by means of a constructor or a factory method. By default, beans are autowired by name and values are set using setter methods. So in your case the field will be set after constructor.
This is because
#Autowired
BeanA beanA;
really means that you want to autowire the field of that class instance. beanA in your case is not really a constructor arg.
(Well, here is a quick question, are the constructor argument names retained after compilation? Is there any debug flag related to this?)
As this example from spring documentation says, you can apply #Autowired to constructors and fields:
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
Let me know if you need any more help with this.
Oh, and just a minor point. You seem to be calling method() on beanA in your constructor. It is not a good idea, if the method can be overridden. I know it is just an example you jotted down here, but just a word of caution.
No, the autowiring is handled by a BeanPostProcessor that will run after the constructor of the newly created bean. If, for some reason, you need to autowire some fields and then run some initialisation you can use a #PostConstruct annotated method. It will be called after all dependencies are injected. In most cases #Autowiring a constructor (and, perhaps, making the object immutable) is still the best option.
No, spring is very clever, but not that magical ... Internally, spring :
creates an instance
set instances properties
stores eventually the bean in relevant scope (exept for prototype beans) and/or gives it to caller
But the creation uses a constructor and at the time it is called properties have not been set.
In short, you can access #Autowired in your method marked with #PostConstruct.
In the below scenario, there is a generic controller. I am doing #PostConstruct to instantiate IfCompleted class. But the IfCompleted object is created as class variable. So fortify is throwing singleton member field. What is the solution to avoid this?
GenericController.java
#Controller
public class GenericController{
#Autowired
public UserService service;
#Autowired
public webRoot webroot;
public IfCompleted ifCompleted;
#PostContstruct
public void show(){
ifCompleted = new IfCompleted(webroot);
}
.....
.....
}
What the example in the question essentially does is take the control away from Spring, which is generally not a good thing. IfCompleted should be a bean whose lifecycle and wiring is controlled by Spring.
Assuming you can't or would prefer not to use XML or Java-based Container configuration to define the singleton IfCompleted with a #DependsOn constraint, it is now possible to create a bean definition from a #Component also, if for example you could only rely on component scanning.
Other useful tools for more complex lifecycle management are the org.springframework.beans.factory.InitializingBean and org.springframework.beans.factory.BeanFactoryAware interfaces.
The short/quick answer may be simply a case of defining the member as static, but I'm not familiar with Fortify's static analysis rules.
Thank you for the advice. I solved it by removing #PostConstruct block, and #Autowired for WebRoot declaration.I injected WebRoot as constructor argument for IfCompleted in the spring context.
#Controller
public class GenericController{
#Autowired
public UserService service;
#Autowired
public IfCompleted ifCompleted;
I have a code containing the below snippet running:
class MyNewReader implements ItemReader<MyBean>, ItemStream{
#Resource
SingleItemPeekableItemReader<MyBean> myBeanPeekableReader;
#Resource
public void setDelegate(MyJdbcReader myJdbcReader){
myBeanPeekableReader.setDelegate(myJdbcReader);
}
I don't have any property delegate in my class MyNewReader.
But still the annotation #Resource is working on setDelegate method and is working fine.
Can someone tell that is it not necessary to have a property in the class to let annotation on setter method(having that property in its name) work...Is this not working as setter injection?
myBeanPeekableReader.setDelegate(myJdbcReader) gets its jdbcReader injected as parameter to the method you have annotated.
Yes, setter injection.