I am learning Spring, and as far as I understand, when we use #annotation on a method which has a generic name (not a setter method), then the method's arguments are autowired.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog mC,
CustomerPreferenceDao cPD) {
this.movieCatalog = mC;
this.customerPreferenceDao = cPD;
}
// ...
}
So, here, the fields movieCatalog and customerPreferenceDao are autowired with the values of mC and cPD. What I fail to understand is how is this different from the same method without the "#autowired".
I understand #autowired when applied to a Field name, but not able to understand when the values are explicitly being passed to the method (either a setter or any other method), then what does Spring do special?
quite late answer, but here it is:
any method annotated with #Autowired is a config method. It is called on bean instantiation after field injection is done. The arguments of the method are injected into the method on calling.
The #autowired method you have provided does not need to be invoked from within your own code. It will be invoked by the Spring framework. Imagine a setter method in a class that is declared as #autowired. The setters parameter is provided by Spring. So before using the class object instance you do not have to write code to call the setter method, just like you don't need to provide the parameters of an #autowired constructor. There are lots of things you can do with autowired. Check out these two examples:
Calling #autowired method
Other uses of #autowired
One of the advantages of #autowired is that you do not have to instantiate the object, as Spring Framework will do that for you. But not only that, an #autowired object is managed by the Spring Framework, so you don't have to worry about handling of object instances, cause Spring does it for you. So it saves a lot of coding and unnecessary code that is often used to keep track of and manage the objects. Hopefully this was of some help.
#autowired on a method is used for setter-injection. it is not different from field injection besides that the beans is not that dependent on the spring-container, you could instantiate and wire it yourself as well.
one reason to use it is if you have circular dependencies.
another use of setter injection is that it allow re-injection of (a possibly optional) dependency at a later time (JMX).
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
#Autowired
private CustomerPreferenceDao customerPreferenceDao;
}
Now you have no need for a prepare method!
Related
Consider the below code:
Service
class MyService{
#Autowired
private ModelMapper modelMapper;
void validate(){
ResponseObject obj = modelMapper.map( REQUEST, ResponseObject.class);
// In testing, if I am not mocking this Model Mapper, an exception will be thrown.
}
}
Testing
Here in JUnit test cases, instead of mocking, I am making use of ReflectionTestUtils.setField("", "", "") and the mapping takes place as expected. But I am not aware of what's happening and how it's working. I referred to many sources, but I couldn't find any reliable resource regarding this. Can someone tell me whats ReflectionTestUtils, how its works, and when to use it?
#InjectMocks
MyService service;
private ModelMapper modelMapper;
#BeforeEach
void setup() {
modelMapper = new ModelMapper();
ReflectionTestUtils.setField( service, "modelMapper", modelMapper);
}
It uses reflection API under the cover to set the value for an object 's field.
About when to use it , the documentation already provides some info :
You can use these methods in testing scenarios where you need to
change the value of a constant, set a non-public field, invoke a
non-public setter method, or invoke a non-public configuration or
lifecycle callback method when testing application code for use cases
such as the following:
ORM frameworks (such as JPA and Hibernate) that condone private or
protected field access as opposed to public setter methods for
properties in a domain entity.
Spring’s support for annotations (such as #Autowired, #Inject, and
#Resource), that provide dependency injection for private or protected
fields, setter methods, and configuration methods.
Use of annotations such as #PostConstruct and #PreDestroy for
lifecycle callback methods.
I normally use it for setting up some dummy domain objects which are JPA entities for testing. Since their ID are managed by Hibernate and to have a good encapsulation , they do not have any setter or constructor to configure their ID value , and hence need to use it to setup some dummy values for their ID.
Instead of doing the very anti-pattern (if you ask me) :
#Autowired
private ModelMapper modelMapper;
you can always inject it via the constructor:
private final ModelMapper modelMapper;
class MyService(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
when MyService is a bean that spring is aware of, the auto-wiring will happen for you. So no need to use the ReflectionTestUtils.setField; which will start failing in jdk-17 and up.
Since you now pass it via a constructor, injection with a mock for example, is trivial.
Spring's Annotation Type Required is marked as deprecated
Deprecated.
as of 5.1, in favor of using constructor injection for required settings (or a custom InitializingBean implementation)
Same for relevant RequiredAnnotationBeanPostProcessor
But it's not clear what's the replacement, it seems that it should be unavailable.
Is this change prevent us marking method as required unless it's part of constructor method ? to prevent unexpected exceptions on class creation ?
There are three ways to inject a bean via annotation:
Field injection
#Autowired
private FooService fooService;
Setter injection
private FooService fooService;
#Autowired
public void setFooService(FooService fooService) {
this.fooService = fooService
}
Constructor injection (this is the mentioned replacement)
private final FooService fooService;
#Autowired
public MyComponent(FooService fooService) {
this.fooService = fooService;
}
As you can see, the only way to declare your Service final is by using the constructor injection, which replaces the #Required annotation because it forces the user of your class to instantiate it with the required services. The user does not have to be Spring, it could be a simple unit test as well.
You should use constructor injection for mandatory dependencies and setter injections for optional dependencies instead of field injection.
Some reasons why:
It makes it clear to everybody which dependencies are required
It makes testing easier
You can make your objects immutable
Further reading:
http://olivergierke.de/2013/11/why-field-injection-is-evil/
https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/
https://spring.io/blog/2007/07/11/setter-injection-versus-constructor-injection-and-the-use-of-required/
Update: non-annotated constructor injection
As one commentator was wondering about a final field annotated with #Autowired while the constructor was not annotated:
If a class only declares a single constructor to begin with, it will always be used, even if not annotated.
https://docs.spring.io/spring-framework/docs/5.2.5.RELEASE/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html ("Autowired Constructors")
But even though it is not necessary to annotate the constructor in this case, I would still do it: it documents the code and if anyone will ever add another (non-annotated) constructor, the code will still work.
Yes , it is deprecated but still you can use it by mentioning below in xml file.
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
I just came across some samples where the #Autowire is used on non-setter methods.
#Autowired
public void doSomething(MyType t){
System.out.println(t);
}
how will i call this method ? like objectReference.doSomething(); does the parameter is not required while calling these methods ?
when do we use #Autowire on non-setter methods
can anybody share some samples on the same ?
spring doc says clearly, #Autowired can be applied on Constructors, Fields, Setters and Arbitrary methods with arbitrary names and/or multiple arguments.
come to your questions, think of doSomething(<>) is an arbitrary method, which should be invoked by container not yourself.
Have a look at this thread
#Target(value={CONSTRUCTOR,METHOD,PARAMETER,FIELD,ANNOTATION_TYPE})
#Retention(value=RUNTIME)
#Documented
public #interface Autowired
as we see from official docs #Autowired Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities. - https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html
But, how spring will know that you method is or is not a config method? When Spring finds #Autowired it will try to find beans matching to method parameters and will invoke that method.
In the Spring reference guide it says that you can apply #Autowired annotation to methods with arbitrary names and/or multiple arguments as shown in the following code.
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
#Autowired
public void prepare(MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
But the prepare() method is not going to be called by the Spring container because its not a setter method. How does #Autowired work in this situation?
It does not say you can use #Autowired for any method what it says is
Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container.
<beans>
<bean id="myBean" class="..." init-method="prepare"/>
</beans>
The annotation #Autowired does not really care which method name you use. So, a method name like prepare works just as well as a method name along the lines of setMovieCatalog.
Furthermore, Spring handles multiple arguments in the method with #Autowired as well. This is typically used for constructor based injection but works out just fine for other methods (like your prepare-method).
So, what is required to make this work? Well, first of all the arguments to the method must be beans that are known by the Spring context. This means that the beans must be wired in the XML-context, annotated with a #Component, or a #Bean from a #Configuration class. Secondly, the class that holds the #Autowired method must also be a bean that is known to the Spring context.
If both of the above are fulfilled, the #Autowired simply works as expected. It can be used on any instance method no matter the name.
No matter whats the method name, #Autowired will try get auto wire during spring context initialization.
I've seen the #Autowired annotation placed just before the constructor of a POJO used as controller.
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
this.usuarioService = usuarioService;
}
// More code
}
This constructor takes as argument the reference to the object we want Spring to inject.However if I place this annotation just before the property declaration the application works just the same.
#Controller
public class LoginController{
#Autowired
private UsuarioService usuarioService;
// More code
}
My question is what is the difference between this two approaches in terms of pros and cons.
My advice to you would be to never use #Autowired on fields (except in Spring #Configuration classes).
The reason is very simple: TESTING!!!!
When you use #Autowired on fields of a class, then that class becomes harder to unit test because you cannot easily use your own (possible mocked) dependencies for the class under test.
When you use constructor injection then is becomes immediately evident what the dependencies of the class are, and creating that class becomes straight forward (simple constructor call).
Some points that need to made:
1) Some might argue that even when #Autowired is used the class can still be unit tested with the use of Mockito's #InjectMocks, or Spring's ReflectionTestUtils.setField, but my opinion is that the creation of a unit under test should be as dead simple as possible.
2) Another point that could be mentioned is that there might be many arguments in the constructor making the manual invocation of the constructor (either in the test or elsewhere) difficult. This however is not a problem regarding the creation of the class, but a problem in the design. When a class has to many dependencies, in most cases it is trying to do too much and needs to broken into smaller classes with fewer dependencies.
#Autowired annotation on setter methods is to get rid of the element in XML configuration file. When Spring finds an #Autowired annotation used with setter methods, it tries to perform byType autowiring on the method
#Autowired annotation on properties is to get rid of the setter methods. When you will pass values of autowired properties using Spring will automatically assign those properties with the passed values or references.
Here is an example of both the usage:
http://www.tutorialspoint.com/spring/spring_autowired_annotation.htm
This Springsource blog post mentions that constructor injection makes it easy to validate required dependencies, if used in combination with contructors assertions that are good practice anyway and would also work if the class is instantiated outside Spring with the new operator:
#Controller
public class LoginController{
private UsuarioService usuarioService;
#Autowired
public void LoginController(UsuarioService usuarioService){
if (usuarioService == null) {
throw new IllegalArgumentException("usuarioService cannot be null.");
}
this.usuarioService = usuarioService;
}
}
This type of assertions are general best practice that is advised to do independently of the class being a Spring bean or not.
For setter or property injection there is also the #Required annotation for validating missing dependencies or #Autowired(required = true). According to the blog post, constructor injection provides this advantage, but for historical reasons setter injection is more frequently used in Spring.