I've been wondering: how exactly does Spring inject properties when using the #Value annotation? What's the mechanism behind this that checks if a field has the annotation? Is it using reflection and some class that finds all annotated classes and creates an instance of them injecting the property, or is it doing it some other way? I know annotation processing would only be used during compilation and will not change the code, so what's happening behind the scenes here really...?
Thanks in advance!
The #Value annotation type has the #Retention(value=RUNTIME) annotation, which means that the information is available at runtime (i.e. using reflection).
A BeanPostProcessor, in particular the AutowiredAnnotationBeanPostProcessor can check for the presence of this annotation on fields, methods or constructors of a bean after instantiation.
If annotation-config feature is on then each time Spring instantiates a bean it goes thru all of its fields and methods and checks if they are annotated with one of Spring supported annotations using reflection.
Related
is it mandatory to write a setter function when we use #Inject annotation
Nope. It is not mandatory. Reflection is used to set the value.
See this and this for more info.
No, we don,t have to write the setter method for #Inject, it is same annotation as the #Autowired.
#Inject is part of a Java technology called CDI that defines a standard for dependency injection similar to Spring. In a Spring application, the two annotations works the same way as Spring has decided to support some JSR-299 annotations in addition to their own.
#Inject can be injected the reference to the implementation of the Provider interface, which allows injecting the deferred references.
We have inherited a large suite of code that has minimal testing. I'm looking to update and create tests.
We have a simple bean that has a private field that uses #value to inject a constant. This bean is constructed and passed around by numerous pieces of code which use the private #value. I want to set up a test suit to always inject some constant into the #value for any instantiated version of the bean.
I know how to inject a #value to a single bean, but considering how often the bean will be instantiated by spy in my test I don't want to have to inject mocks and inject #value into that mock for every case, I'd rather do this on a class level.
I'm aware that it's not good to abuse #value on private variables. We will hopefully fix this at some point, but at this point I don't want to mess with complicated number of constructors for an untestable behemoth of a class if I can avoid it. I'd like a way to test #value on a private field for now, and I'll look to moving how #value is utilized later once we have more stable/testable code base.
Can I configure this injection so it happens to all instantiated instances of the class automatically?
Create a custom test configuration that includes your normal configuration and define the spy as a bean in there with #Primary with the custom #Value value injected in. You can include this as a class file directly in your test folder. That way, anywhere it's being autowired by the spring context, it will get the one from the test configuration instead of the one defined in your normal context.
I would like to make sure if I understand this correctly. Spring needs a setter to inject a field reference? Couldn't it do it by just detecting it as a public field?
Is there an alternative to this. From what I understand Java EE's #Inject annotation can do this without any problem. But I have always been inclined more to Spring.
This depends on how you're creating your bean. Spring does not require setters. There are a number of other ways:
Autowiring (with or without Qualifiers) via annotation at the field level
Constructor injection (either by xml or annotations in the code)
Public fields (as you suggested) might work, though i have never tried it, and would advise against it even if it does.
Unfortunately, the XML approach does not look into private fields (that i know of). You either need to add a setter, use the constructor, or set up some sort of autowiring.
Keep in mind, autowiring can be combined with XML. Spring will pay attention to your wiring annotations even if you create your bean via xml (as opposed to something like #Component and component scanning).
It is not necessary to have Setter to inject a reference, you can use Autowire on a public variable of a class or on the setter method, u can also inject beans using constructor-arg which is a good way of injecting dependencies and autowiring can be done on Constructors also. #inject also does the same functionality as #autowired, however #Autowired has an additional behaviour where it internally also uses #required attribute, to see if the bean has a references and injected properly.
Spring provides several alternatives for DI besides setter injection. For example, you can use constructor injection. Alternatively, you can use Spring's #Autowired annotation for constructor, field or setter injection. Since you mentioned it, I guess that you would also be interested in knowing that Spring supports the #Inject annotation.
Injecting bean with scope prototype with #Autowired usually doesn't work as expected. But when writing code, it's easy to accidentally inject a prototype.
Is there a way to get a list of all #Autowired fields and methods and to match that with a Spring AppContext to check for this?
One approach could be to override org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor(which is responsible for processing #Autowired, #Inject, #Resource etc) and perform the checks that you have mentioned in this overridden bean post processor. However, AutowiredAnnotationBeanPostProcessor gets registered with quite a few of the common custom namespaces (context:component-scan, context:annotation-config etc), so these custom annotations will have to be replaced with the corresponding bean variation and the overridden post processor also registered as a bean.
In another question I asked, raised a concern that spring framework is not type safe. Is it true, or fixed, and can you give an example what it means exactly?
First of all, what does "type-safe" mean for a dependency injection framework. What I can think of is that you can get a bean from the context by specifying a type, and not just a bean name. Spring 3 allows this.
Otherwise, type-safety means that when you can define your dependencies by their type. And you can do this in all versions of spring.
Another thing is compile-time safety. With spring pre-3.0 when you had to differentiate between two beans that share the same interface (or supertype) by using their string-based name. In spring 3.0 you can use annotation-based qualifiers (using javax.inject.Qualifier), so it is compile-time safer as well.
Another thing to mention is the use of generics. You can have, for example #Inject List<MyService> in spring.
Define a custom annotation using #Qualifier
To identify the injected bean without specifying the name, we need to create a custom annotation. This is an equivalent procedure to the use of JSR 330 annotations(Inject) in CDI.
#Target({ElementType.Field, ElementType.Parameter})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #Interface Student {
}
Now assign this custom annotation to implementation of EntityDao Interface
#Component
#Student
public class StudentDao implements EntityDao {
}
#Component tells Spring that this a bean definition. #Student annotation is used by Spring IoC to identify StudentDao as EntityDao's implementation whenever reference of EntityDao is used.
Inject the bean using #Autowired and custom qualifier
Something like this.
#Autowired
#Student
private EntityDao studentDao; // So the spring injects the instance of StudentDao here.
This makes less use of String-names, which can be misspelled and are harder to maintain. - I find this post very useful.
http://www.coolcoder.in/2011/08/how-to-use-type-safe-dependency.html
It depends on how you use it and what you mean by type-safe (see Bozho's answer for more info on the latter): if you use the xml config to produce your beans, then you're probably type-safe after start-up.
However, if you use the new Java Bean config (which has its own limitations) you get compile-time safety.
I'm not advocating the latter over the former, but it's something to consider.