Suppose I'm injecting list of some beans:
#Autowired
List<SomeBean> beans;
What is default injection order in this situation?
I know about Ordered interface and #Order annotation, I'm asking only about default behavior.
What I've noticed is that in case of manual bean registration:
context.register(SomeBeanA.class);
context.register(SomeBeanB.class);
context.register(SomeBeanC.class);
This beans is injected in the exact same order as I registered them: 1 element in list is SomeBeanA, 2 — SomeBeanB, 3 — SomeBeanC.
Is there is any guarantee of this behavior? I mean can I be sure that it won't change in further release?
Thanks.
If you want to guarantee the order of the autowired list I would use the order interface or annotation.
In fact the list is ordered anyway and each bean not declaring an explicit order resolves to a default order. (Which is min integer by default if I'm not mistaken)
Take a look at this class:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationAwareOrderComparator.html
Related
we are using Spring in our project and today I found, in my eyes, a strange beaviour. In my opinion Dependency Injection and the annotation #DependsOn should be the same in the following both cases
#Bean
public ClassA classA(){
//code
}
#Bean
public ClassB classB(ClassA classA){
someMethodWhichNeedsClassA()
}
and
#Bean
public ClassA classA(){
//code
}
#Bean
#DependsOn("classA")
public ClassB classB(){
someMethodWhichNeedsClassA()
}
It seems, that those both ways are not identical. I am not allowed to share my code, but in the first case I have access to a list which is filled in the first Bean, but not in the second case.
I tried to find something in the documentation or in other blogs but without success.
Has anybody an idea if there is any differences between those both ways, because I thougth it has something to do with ordering of bean creation and thats all.
Thanks for any help
Spring, by default, manages beans' lifecycle and arranges their initialization order. This is the case in your first example. While in your second example you tell Spring that bean B depends on A. So spring will create bean A before bean B.
#DependsOn from spring docs:
Beans on which the current bean depends. Any beans specified are
guaranteed to be created by the container before this bean. Used
infrequently in cases where a bean does not explicitly depend on
another through properties or constructor arguments, but rather
depends on the side effects of another bean's initialization.
Baeldung spring DependsOn
In simple words there are two scenarios
If beans creation is in sequence, spring will start initializing from top to bottom. In this case, depending on bean needs to listed first
If beans creation is not in sequence and getting managed through multiple appconfig, in this we can use #DependsOn annotation to make sure that dependent beans are initialized before getting used.
If bean B calls any method on bean A (or passes to some other objects/methods that eventually call methods of bean A), then dependency injection is sufficient.
Bug there are cases when bean B does not need to call any methods on bean A,
but dependsn on the result of initialization of bean A. Suppose bean A during its initialization creates tables in database,
and bean B needs these table before it can be use. Then dependency injection makes no sense. Any code quality check will show you that
injected variable is not used and thus is not needed.
In such case you don't inject bean A into B, but declare dependency on bean A.
Briefly: If bean B calls bean A, use dependency injection. If bean B only needs results of initialization of bean A, use #DependsOn.
Lets say we have
class TestClass1 {
#Inject #Any #BBB(PARAM1)
Instance< Product > instaces;
#Produces #BBB(PARAM1)
Product first(){...}
#Produces #BBB(PARAM1)
Product second(){...}
}
and
class TestClass2 {
#Inject #Any #BBB(PARAM2)
Instance< Product > instaces;
#Produces #BBB(PARAM2)
Product first(){...}
#Produces #BBB(PARAM2)
Product second(){...}
}
When i put #BBBs on class and remove from methods instances are empty. Is how it works and I have to replicate #BBB on every #Produces methods OR something I have missed?
#BBB is annotated with #Qualifier and RUNTIME retention
Not sure I fully understand your question, but I hope this will clarify it. I think you are mixing several things together.
1) Producers
Those are methods/fields which are effectively considered beans! This means that on top of producer you have to define what kind of bean will it create. That boils down to qualifiers, scope, stereotypes,... Whatever you need/want there. This also allows you to have multiple producers which will only differ in, say, qualifier with which they create the bean. So yes, you need to repeat it on each producer, for it may make a great difference.
2) Your classes
Your are themselves beans (dependent scope in this case) and you can specify all the CDI stuff on them - scope, qualifiers, etc. This will not propagate to the producers inside the beans. If you think about it, that would mean that should your class be application scoped, anything it produces would also be application scoped, which is not the case.
Your source of confusion might also be interceptor/decorator (or rather their binding) which can be placed either on bean method (enabling interception for given method) or on top of whole class (enabling interception for all methods).
I have an interface called StatsStore. I have 2 implementations of this store. An in-memory and an SQL implementation called InMemoryStatsStore and SqlStatsStore. In order to inject them I've create 2 annotations #InMemoryStore and #SqlStore. the injections are:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(StatsStore.class)
.annotatedWith(SqlStore.class)
.to(SqlStatsStore.class);
Now I want to add a new layer of annotation to separate between InMemoryStringStore and InMemoryNumberStore but I can't add more than one annotation to the binding lines e.g. the following does not compile:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
.to(InMemoryNumberStore.class);
How can I add more than one annotation without using a single named one which would be quite complicated the more layers I add to it?
The other solution I had in mind is Injecting twice:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(InMemoryStatsStore.class)
.annotatedWith(NumberStoreAnnotation.class)
.to(InMemoryNumberStore.class);
Thanks all.
As Amit said, you can't have more than one #BindingAnnotation apply to any given injection. Internally, Guice works like a Map<Key, Provider> where a Key is a possibly-parameterized class with an optional single annotation instance. However, because these are instances, you're welcome to create your own instantiable annotation that works the way Named works.
#Inject #InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
#Inject #SqlStore(STRING) StatsStore sqlStringStore;
// or
#Inject #Store(dataType=NUMBER, backend=SQL) sqlNumberStore;
The annotation must have the fields defined like so. (If you have one element named value, you can omit the property name per JLS 9.7.3.) Equal annotations are defined as in the Annotation.equals docs.
public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }
#BindingAnnotation #Retention(SOURCE) #Target({ FIELD, PARAMETER, METHOD })
public #interface Store {
DataType dataType();
Backend backend();
}
That works nicely for #Provides, when you can invoke the annotation the same way you inject it, but how can you create a factory method for instances like Names.named? For that, you'll need to do one of the following:
Create an anonymous implementation, with accessors for each attribute as well as correct implementations of equals and hashCode. Note that the hashCode contract is much stricter than for Object, but you can get compatible implementations from Apache annotation utils or similar libraries.
Use AnnotationLiteral, which provides equals and hashCode implementations for arbitrary subclasses.
Use Google Auto or a similar code generator to generate code for a compatible implementation for you. Familiarity with this type of solution is particularly useful for Android and other memory-constrained environments for which reflection is slow, though such environments usually preclude you from using Guice. (#Qualifier annotations work the same way in other JSR-330 compatible dependency injection frameworks, though, including Dagger.)
If the above seems a little complicated, or if you want more complex logic than Guice's map-based implementation can accomplish, one alternative is to add a layer of indirection that you control:
public class StoreStore {
#Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
// ...
// You can also inject the Injector to call getInstance with a class literal.
public StatsStore getStore(DataType dataType, Backend backend) {
// This can also be a switch or any other sort of lookup, of course.
if (dataType == NUMBER && backend == IN_MEMORY) {
return inMemoryNumberStoreProvider.get();
} // ...
}
}
You can't do that:
#BindingAnnotation tells Guice that this is a binding annotation. Guice will produce an error if ever multiple binding annotations apply to the same member.
You could use named bindings instead, or you should consider redesigning your solution.
I would really like to have even a basic understanding of how is #autowired
implemented in Spring.
Reflection should be somehow implied in its implementation, but I cannot figure out how.
Can you help ?
Autowiring through #Autowired is performed by a BeanPostProcessor implementation, specifically org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.
This BeanPostProcessor processes every bean, will scan its class (and superclasses) for any #Autowired annotations, and, depending on what is annotation (a constructor, field, or method), it will take appropriate action.
For constructors
Only one constructor (at max) of any given bean class may carry this
annotation with the 'required' parameter set to true, indicating the
constructor to autowire when used as a Spring bean. If multiple
non-required constructors carry the annotation, they will be
considered as candidates for autowiring. The constructor with the
greatest number of dependencies that can be satisfied by matching
beans in the Spring container will be chosen. If none of the
candidates can be satisfied, then a default constructor (if present)
will be used. An annotated constructor does not have to be public.
For fields
Fields are injected right after construction of a bean, before any
config methods are invoked. Such a config field does not have to be
public.
For methods
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. Bean property setter methods are effectively just a
special case of such a general config method. Config methods do not
have to be public.
All of this is done through reflection.
Further reading:
How do I invoke a Java method when given the method name as a string?
Is it possible in Java to access private fields via reflection
is there a way to use dependency injection to inject all available implementations of a specific interface in spring?
This is kind of the same thing as asked here for .NET.
Though my aim is to use #Autowired for this:
public class Foo{
#Autowired
private IDataCollector[] collectors;
}
Is this supported, would this require hacking or should I preferably use another component where all implementations of IDataCollector register themselve and use that accessor component with autowired instead of the array injection?
A reason I can think of why this may not be implemented per default may be, that it would also inject possible mock implementations where inappropriate. Though I'm still interested wether this is possible or not. :)
you can inject a List and Spring will convert this for you:
<util:list id="collectors">
<value>someone#something.com</value>
<value>someoneelse#something.com</value>
</util:list>
Your example should work fine, as should List<IDataCollector>. Did you give it a try before asking, and found it didn't work?
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation
It is also possible to provide all
beans of a particular type from the
ApplicationContext by adding the
annotation to a field or method that
expects an array of that type.