0

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.

IqbalHamid
  • 2,324
  • 1
  • 18
  • 24
  • This might be a duplicate of https://stackoverflow.com/q/45210671/5646962 – Thomas Kläger Aug 06 '18 at 16:42
  • Possible duplicate of [Whats is the order dependency injection in spring?](https://stackoverflow.com/questions/45210671/whats-is-the-order-dependency-injection-in-spring) – Thomas Kläger Aug 06 '18 at 16:43
  • @ThomasKläger, yes, I have looked at that question you are refering to. Although the question appears similar to mine, none of the answers given to that question, answer my question. One key difference is my scenario relates to Spring using annotations whereas your link relates to Spring using an application context xml file and the answers talk about how to specify the order in an xml. But my question asks what happens when using annotations and order is not specified? Is it even possible to specify the order without an xml file? How is Spring prioritising is injections? – IqbalHamid Aug 06 '18 at 16:52
  • If the order cannot be guaranteed using xml (where xml clearly imposes an ordering on the declarations), it is even more unlike that any ordering can be guaranteed using annotations. One obvious reason is that for using annotation based injection 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 – Thomas Kläger Aug 06 '18 at 17:12
  • Could you please show how you declare your `fortuneService_x` beans? – Max Farsikov Aug 06 '18 at 21:39
  • @MaxFarsikov, Not usre what you mean by declaring these beans. As they are manged by Spring, I am not having to declare them Either in my main class or in my BadmintonCoach class. I have an interface called IFortuneService. Then I have created two different implementations of that interface: They are FortuneService_Random and FortuneService_RESTful. The two methods of my BadmintonCoach class, shown in my question, request these helper beans from Spring via the -@Autowired and -@Qualifier annotations. – IqbalHamid Aug 07 '18 at 08:48

1 Answers1

0

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.

IqbalHamid
  • 2,324
  • 1
  • 18
  • 24