Is it wrong to autowire both the field and the constructor when doing the automatic configuration of the spring container. For example:
#Component
public class Test1 {
#Autowired
private Test2 B;
#Autowired
Test(Test2 C) {
this.B=C;
}
}
And could you explain what happened exactly ?
It's wrong. You may have two Test2 beans, one named "B" and one named "C" (names should be lowercase BTW). That constructor will be called first, setting the field to C; after that the field will be injected, overwriting the field with B. If there is only one Test2 bean then it will work, but keep in mind that the point of constructor injection is to avoid field injection and enable use of final fields instead.
Related
As the title suggests , I want to know how does field injection internally works in spring , I read many articles on this and got to know few things like below but didn't understood the exact reason behind it :
-> It should not be used because when you do unit testing then you are dependent upon the spring
container to instantiate the class in case of field injection.
-> You cannot use "final" keyword in case of field injection , means you cannot make the field immutable.
-> It internally uses reflection
I want to know how exactly does #Autowired works internally , how does it uses reflection , I am trying to understand the exact reason behind all the above mentioned points, what happens behind the scenes when we write the below code :
#Component
public class B {
#Autowired
private A a1;
}
I have read similar questions on stack overflow about this topic , but I couldn't find the exact explanation that I am looking.
Spring has a concept of Bean Post Processors.
When spring builds a bean it applies registered bean post processors that help to "initialize" the bean.
So, there is org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor that handles autowiring.
Basically it works with an newly created object. Spring introspects the fields of the beans (by using reflection). The fields that have #Autowired is a subject for processing with this bean post processor. It finds the candidate for injection in the application context and actually injects the value.
Now given this information, its understandable why final fields cannot be autowired. Leave alone spring, In pure Java, final fields must be instantiated directly right during the declaration (final int i = 123) or in the constructor of the class. But the autowiring happens after constructor, so its impossible to autowire the final fields.
As for the unit testing, the private properties must be somehow configured from the test. But since they're encapsulated (yes, spring kind of breaks encapsulation in this case for its usage), its impossible to write a good test for the class that contains fields injection. That's is a reason to switch to constructor injection.
public class FieldInjection {
#Autowired
private A a;
}
VS.
public class ConstructorInjection {
private final A a;
// this can be generated by lombok, you don't have to put #Autowired on constructor in the case of single constructor, spring will use it to create a bean
public ConstructorInjection(A a) {
this.a = a;
}
}
Now the test for FieldInjection class is impossible:
public class FieldInjectionTest {
#Test
void test() {
FieldInjection underTest = new FieldInjection();
how do you know that you should instantiate A a. ????
}
}
However in the case of constructor injection its a trivial task:
public class ConstructorInjectionTest {
#Test
void test() {
A a = mock(A.class);
ConstructorInjection underTest = new ConstructorInjection(a);
// the dependencies must be supplied in the constructor
// otherwise its impossible to create an object under test
}
}
Why my code is failing with the below error when I AUTOWIRE the no arg constructor but it runs fine when I autowire only the single arg constructor
Exception in thread "main" java.lang.NullPointerException
Here is TennisCoach Class code snippet
#Component // this is bean id
public class TennisCoach implements Coach {
public TennisCoach(FortuneService thefortuneservice) {
System.out.println(" inside 1 arg constructter");
fortuneservice = thefortuneservice;
}
#Autowired
public TennisCoach() {
System.out.println(" inside 0 arg constructter");
}
}
Coach theCoach = myapp.getBean("tennisCoach", Coach.class);
System.out.println(theCoach.getDailyFortunes());
How are things working behind the scene?
If you have only one constructor in a class, you don't need to use #Autowired--Spring understands that there's only one option, so it uses that one. But you have two constructors, so you need to tell Spring which one to use.
When you invoke the default constructor, however, what do you expect to happen? You don't set up your variables anywhere at all, but you are trying to read from them.
Constructor with no arguments doesn't want you put #Autowired on it as you are not injecting anything in its arguments (since there are none). #Autowired is required for constructor with arguments however.
#Component annotation above the class will create your bean via calling the default constructor and you can use that anywhere but need to make sure that you don't call anything on the fortuneservice as that will result in a null ptr exception unless you initialize it. On the contrary, if you put #Autowired annotation on top of constructor with argument and it runs fine then that means that the fortuneservice bean that you have declared elsewhere will now be injected inside this class and no null ptr exception if you call some method on that.
Adding to the previous to answers - think about the term "constructor injection". You are INJECTING references via constructor parameters. When you #Autowire an empty constructor, there isn't anything to inject. Therefore you get a NullPointerException when attempting to access the field that was supposed to have a reference injected into.
I have a class with overloaded constructors, like this:
#Component
public class MyClass {
private ClassA myMemberA;
private ClassA myMemberB;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA, ClassA objectB) {
myMemberA = objectA;
myMemberB = objectB;
}
#Autowire
public MyClass(ClassA objectA) {
myMemberA = objectA;
}
}
Basically, one constructor has two arguments of ClassA, and one constructor has just one argument. I have two beans of type ClassA defined.
I would like to have one of the two constructors invoked and autowired accordingly depending on the use case.
When I ran this code, I got the error:
Invalid autowire-marked constructor: ...
Found another constructor with 'required' Autowired annotation: ...
Is it possible to have overloaded autowired constructors? If yes, what is the right way to do it?
Thank you!
You need to define which constructor Spring will be prioritizing by writing something like this: #Autowired(required=true) or #Autowired(required=false). You are only allowed to have one constructor with #Autowired(required=true). By default, if you don't define the required property, it will be set to true, which is the problem in your case.
I don't see the point of having two Autowired constructors if only one of them will be wired anyway. If you're trying to Autowire the two instances of ClassA, it might be better to add the #Autowired annotation to the setters or the variables.
I having a Spring class, where I am autowiring a service using constructor, plus in the same constructor I am intializing other field of the same class.
#Component
class Converter {
private TestService testService;
private Interger otherFields;
#Autowired
public Converter(TestService testService) {
this.testService = testService;
this.otherFields = new Integer(10);
}
}
My Functionality is working fine, but is it a good practice?, would #Autowired annotation have any impact on otherFields intialization process
It shouldn't. Back in the xml days, when you want to pass on an argument to a constructor, you mentioned your ref bean for the constructor arg. This just means that you must have a constructor that takes the specified bean type as an argument. It doesn't really matter what you add in the constructor, as long as you are creating a valid object through the constructor (though this is just normal java programming and nothing to do with Spring).
Auto-wiring is just an easy way to create your object with the necessary dependencies and your code is still your code.
No.
When Spring is instantiating your class it will locate the constructor annotated with #Autowired, collect the beans that corresponds to the arguments the constructor takes and then invoke it with those beans as arguments.
It will then scan through all fields and methods in your class and inject beans into any fields that are annotate with #Autowired. It will not touch methods or fields that are not annotated.
If let's say I have a class A (#Component) and a class B (#Component). Class A needs an instance of B. If I put class B as a field in A with #Autowired, even though Spring will find the B component (through #ComponentScan), the class A field will be null. However, if I put B as an argument in the A's contructor and annotate the constructor with #Autowired, it will work perfectly.
Is there any way to exclude B from A's constructor?
As #LuiggiMendoza mentioned: Creating a #PostConstruct method is easy: you should only annotate your method with #PostConstruct:
public class A {
#PostConstruct
void init(){
//do smth here
}
}
Or if you use XML configuration you can add init-method parameter to your bean definition.