Search This Blog

If you use Spring framework for more than a week you are probably aware of this feature. Suppose you have more than one bean implementing a given interface. Trying to autowire just one bean of such interface is doomed to fail because Spring has no idea which particular instance you need. You can work around that by using @Primary annotation to designate exactly one "most important" implementation that will have priority over others. But there are many legitimate use cases where you want to inject all beans implementing said interface. For example you have multiple validators that all need to be executed prior to business logic or several algorithm implementations that you want to exercise at the same time. Auto-discovering all implementations at runtime is a fantastic illustration of Open/closed principle: you can easily add new behavior to business logic (validators, algorithms, strategies - open for extension) without touching the business logic itself (closed for modification).

Just in case I will start with a quick introduction, feel free to jump straight to subsequent sections. So let's take a concrete example. Imagine you have a StringCallable interface and multiple implementations:

Interestingly, even though Spring internally injects LinkedHashMap and LinkedHashSet, only List is properly ordered. I guess it's not documented and least surprising. To end this introduction, in Java 8 you can also inject Optional<MyService> which works as expected: injects a dependency only if it's available. Optional dependencies can appear e.g. when using profiles extensively and some beans are not bootstrapped in some profiles.

Thanks to @Primary we can simply autowire StringCallable everywhere as if there was just one bean while in fact there are multiple and we inject composite. This is useful when refactoring old application as it preserves backward compatibility.

Why am I even starting with all these basics? If you look very closely, code snippet above introduces chicken and egg problem: an instance of StringCallable requires all instances of StringCallable, so technically speaking callables list should include Caller as well. But Caller is currently being created, so it's impossible. This makes a lot of sense and luckily Spring recognizes this special case. But in more advanced scenarios this can bite you. Further down the road a new developer introduced this:

We now created a circular dependency, and because we inject via constructors (as it was always meant to be), Spring slaps us in the face on startup:

UnsatisfiedDependencyException:
Error creating bean with name 'caller' defined in file ...
UnsatisfiedDependencyException:
Error creating bean with name 'fifth' defined in file ...
UnsatisfiedDependencyException:
Error creating bean with name 'enterpriseyManagerFactoryProxyHelperDispatcher' defined in file ...
BeanCurrentlyInCreationException:
Error creating bean with name 'caller': Requested bean is currently in creation:
Is there an unresolvable circular reference?

Stay with me, I'm building the climax here. This is clearly a bug, that can unfortunately be fixed with field injection (or setter for that matter):

By decoupling bean creation from injection (impossible with constructor injection) we can now create a circular dependency graph, where Caller holds an instance of Fifth class which references Enterprisey..., which in turns references back to the same Caller instance. Cycles in dependency graph are a design smell, leading to unmaintainable graph of spaghetti relationships. Please avoid them and if constructor injection can entirely prevent them, that's even better.

Problem solved? Quite the opposite! getBeansOfType() will silently skip (well, there is TRACE and DEBUG log...) beans under creation and only returns those already existing. Therefor Caller was just created and container started successfully, while it no longer references Fifth bean. You might say I asked for it because we have a circular dependency so weird things happens. But it's an inherent feature of getBeansOfType(). In order to understand why using getBeansOfType() during container startup is a bad idea, have a look at the following scenario (unimportant code omitted):

Spring framework first loads Alpha and tries to instantiate a bean. However when running getBeansOfType(Beta.class) it discovers Beta so proceeds with loading and instantiating that one. Inside Beta we can immediately spot the problem: when Beta asks for beanFactory.getBeansOfType(Alpha.class) it gets no results ([]). Spring will silently ignore Alpha, because it's currently under creation. Later everything is as expected: Gamma is loaded, constructed and injected, Beta sees Gamma and when we return to Alpha, everything is in place. Notice that even moving getBeansOfType() to @PostConstruct method doesn't help - these callbacks aren't executed in the end, when all beans are instantiated - but while the container starts up.

Suggestions

getBeansOfType() is rarely needed and turns out to be unpredictable if you have cyclic dependencies. Of course you should avoid them in the first place and if you properly inject dependencies via collections, Spring can predictably handle the lifecycle of all beans and either wire them correctly or fail at runtime. In presence of circular dependencies betweens beans (sometimes accidental or very long in terms of nodes and edges in dependency graph) getBeansOfType() can yield different results depending on factors we have no control over, like CLASSPATH order.

I couldn't make list injection work, because I forgot to put @Component on the implementation. The fact that this setup worked with injecting a single element (without collection) confused me even more.The first part of the post really helped me to sort this out. Thanks!