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.
Related
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.
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!
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.
It seems not the case. I used to have the notion that XML configurations are meant to override annotations. But when I set autowire="no" in the XML configuration, the bean's #Autowired annotated property still takes effect. I'm no longer sure if XML autowire has anything to do with #Autowired anymore. It's quite counter-intuitive in my opinion.
Can someone point me to a documentation that says something about this?
Here's my example:
<bean class="com.example.Tester"></bean>
<bean class="com.example.ClassToTest" autowire="no"></bean>
public class Tester
{
#Autowired
ClassToTest testSubject;
}
public class ClassToTest
{
#Autowired // I want this not to get autowired without removing this annotation
private OtherDependency;
}
autowire="no" means we have to explicit wire our dependencies using either XML-based configuration or #Autowire and it is default setting.
Auto-wiring by xml configutaion or by annotation means implicitly mapping dependencies using given strategy.
For more details refer here
I have an app that's been working well with #Autowired #Service beans.
Now I'm adding a Validator class which is instantiated in the Controller:
BlueValidator validator = new BlueValidator(colors);
validator.validate(colorBlend, bindResult);
In the BlueValidator class I'm trying to #Autowire the blendService which is working as an #Autowired field elsewhere in the app:
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
private Colors colors;
But for some reason after instantiating the BlueValidator, I keep getting NullPointerExceptions for the blendService.
Of course I've added the necessary context scanning:
<context:component-scan
base-package="com.myapp.controllers, com.myapp.services, com.myapp.validators" />
I also tried adding the#Autowired annotation to the constructor but that didn't help:
#Autowired
public BlueValidator(Colors colors) {
this.colors = colors;
}
Should I just pass the blendService to the BlueValidator and forget about the Autowiring or is there something obvious missing here?
If you just instantiate an object with new, Spring is not involved, so the autowiring won't kick in. Component scanning looks at classes and creates objects from them - it doesn't look at objects you create yourself.
This can be made to work, using Spring's AspectJ support, but it takes some effort.
Otherwise, you need to let Spring instantiate your objects if you wan autowiring to work.
Should I just pass the blendService to the BlueValidator and forget about the Autowiring
In your situation, I'd say yes, this is the least effort solution.
When you instantiate objects spring cannot do anything for them, so it does not get the dependencies injected (article).
In your case, you have a couple of options:
pass dependencies to the validator from the controller (where you can inject them)
make the validator a spring bean and inject it, instead of instantiating it
use #Configurable, which, via AspectJ, enables spring injection even in objects created with new
#Autowired is being used by Spring's ApplicationContext to populate those fields on creation. Since the ApplicationContext is not the one creating these beans (you are because of the keyword 'new'), they are not being autowired. You need to pass it in yourself if you are creating it.
Don't create validator manually -- allow to Spring do this work for you:
#Controller
class Controller {
#Autowired
BlueValidator validator;
void doSomething() {
...
validator.validate(colorBlend, bindResult);
...
}
}
Also pay attention that adding package com.myapp.validators to context:scan-packages not enough, you also should annotate your validator class with #Component annotation:
#Component
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
(BTW this solution works in my project.)