-4

I am still learning how the Java language works.

I have a interface called DataService. which serves as a interface between different database services; MongoDbDataservice.java and MySQLDataService.java

DataService.java

public interface DataService {
    int[] retrieveData(); // Method to retrieve data from different databases

MongoDbDataService.java

@Component
public class MongoDbDataService implements DataService {
    public int[] retrieveData() {
        return new int[] {11, 22, 33, 44, 55};
    }
}

MySQLDataService.java

@Component
@Primary
public class MySQLDataService implements DataService {

    public int[] retrieveData() {
        return new int[] {1,2,3,4,5};
    }
}

BusinessCalculationService.java

@Component
public class BusinessCalculationService {
    private  DataService dataService;

    public BusinessCalculationService(DataService dataService) {
        this.dataService = dataService;
    }

    public int findMax() {
        return Arrays.stream(dataService.retrieveData()).max().orElse(0);
    }
}

My question is what exactly is happening in the background when this line of code is compiled / executed?

public BusinessCalculationService(DataService dataService) {
            this.dataService = dataService;
        }

How is the DataService object being "tied" or "wired" to BusinessCalculationService and what does it mean to be "wired"

Everything up to that point makes sense to me except this. I should mention I am using Spring framework.

Thank you in advanced.

Nick
  • 624
  • 8
  • 24
  • 1
    It's not java doing this. It's spring. Autowiring is (part of) the reason spring is used. It's the bit of "magic" that it adds to the table. I'm afraid explaining how exactly spring does that is a bit too broad a topic to explain here. – Federico klez Culloca Jan 10 '23 at 11:06
  • 1
    On the Java side, there's nothing special happening here. But Spring includes a "dependency injection framework". It manages the instances of `BusinessCalculationService` for you. Part of this is calling the constructor, most likely reflectively (see the `java.lang.reflect` package). It searches for available implementations of the constructor parameter. In this case, it finds two, but one is marked `@Primary`, so it instantiates that one (or grabs it from a cache), and passes the instance of `MySQLDataService` to the constructor of `BusinessCalculationService`. – Slaw Jan 10 '23 at 11:09
  • 7
    If you're still learning how the *language* works, then stay clear of any tutorials that use Spring. Not because Spring is bad (it's a useful tool that does many useful things), but because it adds a whole other layer of complexity **on top of** the basics of the language. So in order to learn about Spring, you should be **really solid** in the basics of Java itself. – Joachim Sauer Jan 10 '23 at 11:09
  • (although your `BusinessCalculationService` constructor might need to be annotated with `@Autowired` for this to work, not sure). – Slaw Jan 10 '23 at 11:12
  • 2
    In that specific line, only an instance-field of your class is set to a new value. This field lets you access the other instance from your object. Same as `Object obj = new Object()` assigns a reference to the variable. – knittl Jan 10 '23 at 11:14
  • @knittl what you said made it click in my head. thank you – Nick Jan 10 '23 at 11:18
  • To be a little more relatable, it's like `List list = new ArrayList<>()`. A concrete implementation of your `DataService` interface is being injected, but it can be _any_ implementation, and you only see it as a `DataService`. – Slaw Jan 10 '23 at 11:21
  • Also, this may be helpful regarding dependency injection: https://stackoverflow.com/questions/43514699/how-does-spring-achieve-dependency-injection-at-runtime – Slaw Jan 10 '23 at 11:21
  • 2
    @Slaw re: "*might need to be annotated*", it doesn't have to be. See my answer here https://stackoverflow.com/a/68544892/1898563 83000 views. A common misconception, it seems. – Michael Jan 10 '23 at 11:27

1 Answers1

3

what exactly is happening in the background when this line of code is compiled / executed?

public BusinessCalculationService(DataService dataService) {
    this.dataService = dataService;
}

That line? A reference to an object is being assigned to an instance field. That's it. It's not really any different than a local variable int foo = 1, except that the variable belongs to an object.

The "magic" is from the caller, the thing that's invoking the constructor. That's Spring, and that's buried deep in their framework; you're not supposed to see that. Notice how you never call new BusinessCalculationService(...) but somehow an instance is being created.

Before invoking that constructor, it's searching its records for a single "bean" - an object registered with the framework - that matches the type that the constructor is asking for.

If it can unambiguously find one and only one matching bean then it will "auto-wire" that instance - supply it to the constructor - automatically wiring together beans, kind of like you'd wire together electrical components.

If there's more than one match, then it will throw an error that what you're requesting is ambiguous. If there are no matches, then it will throw an error too.

More here: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core

Michael
  • 41,989
  • 11
  • 82
  • 128