Skip to content
Advertisement

Dependency injection with @Inject

I find it odd that that I can’t find this information, so please direct me to a creditable source if possible. This questions pertains only to Java.

In short, I want to know how dependency injections actually happens syntactically.

My understanding of dependency injection is the following:

public class Car {
    private Engine engine
    
    @Inject
    public Car(Engine engine) {
        this.engine = engine
    }
}

Is the equivalent of

public class Car {
    private Engine engine
    
    public Car(Engine engine) {
        this.engine = engine
    }
}

Where the keyword @Inject is syntactic sugar to let Java know that the dependency engine is to be injected. This way Car won’t be responsible for creating engine and therefore have a hard dependency of Engine. However, no examples have shown me how to inject it. In short:

public MyClass {
    public static void main(String[] args) {
        ToyotaEngine toyotaEngine = new ToyotaEngine();
        HondaEngine hondaEngine = new HondaEngine();
        // ??? which one to inject?
        Car myCar = new Car(); // syntax?
    }
}

How do I actually trigger the injection? Simply call new Car() and Engine will be pass to the constructor for me? How does Java know which Engine to inject?

Everything I’ve googled pertains to how to use the @Inject annotation on the class but nothing about how to actually trigger it. This article describes a configuration that looks specific to Spring and doesn’t explain much. And I’m not sure what Spring is.

Advertisement

Answer

There is no “syntax” about it, and @Inject is not syntactic sugar. An annotation is a piece of metadata that gets recorded on an element (class, method, field, etc.), and then other software has a chance to inspect it. In the case of @Inject, some framework that you’re using (Spring, CDI, Guice) looks for the annotation and, if present, executes some code that looks up and provides you with the dependency. (This is typically called a container because it contains a bunch of objects that can be looked up and injected for you. Among other things, Spring provides a DI container.)

The constructor (or setter) works entirely normally, and you can’t just use new Car(). Instead, the framework, which has found an Engine somewhere, invokes new Car(engine) for you, passing in that object. If you’re simply using new, then you have to provide your own values; this is very useful for tests, where you can pass in mocks or test data.

(This, by the way, is the reason that using constructor injection is nearly always the best choice; it prevents you from using new Car() when there are hidden dependencies, which wouldn’t be initialized properly.)

Advertisement