Search code examples
javaspringdependency-injectioninversion-of-control

Injection of Multiple Conflicting Dependencies in Spring


I have a Spring bean class which requests dependencies to be injected. However, in my class, I am manually wiring different dependencies to the same private class variable. What happens in this scenario? Which injection takes precedent?

Details:
I have created a Spring bean class called BadmintonCoach.

It relies on an IfortuneService helper. IfortuneService is an interface with TWO different implementations. The two implementations are:

  1. FortuneService_RESTful
  2. FortuneService_Random

In my badmintonCoach class, I have created a private variable to receive the injection from Spring:

private IFortuneService theFortuneService

That is to say, I am manually wiring up the the injected dependency to this private member, theFortuneService

I am injecting these iFortuneService dependencies using method injection.

BUT here is the problem: I have TWO methods, both of which request an injection from Spring of the type iFortuneService. One method requests one implementation (FortuneService_RESTful) and the other method requests a bean of the other implementation (FortuneService_Random).

Both of these methods set this.theFortuneService equal to its respective requested helper. So what I have within my BadmintonCoach class is:

private IFortuneService theFortuneService

@Autowired
@Qualifier("fortuneService_Random")
public void randomMethod_ONE(IFortuneService theFortuneService) {
    System.out.println("Code inside randomMethod_ONE!");
    this.theFortuneService = theFortuneService;
}


@Autowired
@Qualifier("fortuneService_RESTful")
public void randomMethod_TWO(IFortuneService theFortuneService) {
    System.out.println("Code inside randomMethod_TWO!");
    this.theFortuneService = theFortuneService;
}

My question then, is:
Which of the two wirings wins out? Why? How does Spring decide the ORDER of its injections? What determines the order of the injections? Is it random? Is it injected in alphabetic order of the method names? Is there an order of injection between constructor, setter, field and method injections?

What am I seeing when I run my program? I am seeing the injection of fortuneService_RESTful win out, but it is unclear to me whether this is by chance or by design from within Spring's logic.

Here is another thought:
What if, instead of requesting different implementations of the IFortuneService interface, the two methods above asked for the same bean but that bean was prototyped? Clearly, there would be a new incarnation created for each request and there would only be one helper class assigned to my BadmintonCoach class. But which incarnation would win out?

I can provide the whole of my code if it will make my question clearer.

If you are wondering WHY I have written conflicting code? It is plain and simple curiosity to try and understand how Spring works behind the scenes.


Solution

  • OK folks, it has taken a day for me to see this but I can confirm that what happens here is indeed random!

    Yesterday, I was exclusively seeing method_ONE win out. Today, I am seeing method_TWO win out. I can therefore conclude that the order of injections by Spring is indeed random!

    Thomas Klager had provided a suggestion in the comments above which may explain this phenomenon:

    One obvious reason [for this] is that using annotation based injections, spring needs to list the methods of a class using Class.getDeclaredMethods() or Class.getMethods(). Neither of these methods return the methods in any particular order.

    I still find it a mystery how execution of the same logic by Spring (ie: Class.getDeclaredMethods() or Class.getMethods()) can yield random results like this.

    It is very important to be aware of this limitation! When writing code, you may find yourself wanting to use the services of injected dependencies which in turn depend on the services other injected dependencies. It is clear from this experiment that this could potentially be dangerous and therefore you should not layer your wiring in this manner. That is to say, your wiring should always be single tiered if it spans multiple methods, otherwise, you risk spurious output from your program. An illustration of this danger can be seen in Slim's answer in this link.