Open In App

What is the best way to inject Dependency in Java?

Last Updated : 01 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

You can transform standard Java classes into manageable objects by using dependency injection. Your programs can define dependencies on any managed object by using dependency injection. In addition to managing the life cycle of these instances for you, the container automatically supplies instances of these dependencies at the injection points during runtime. Dependency injection is a way of providing dependencies to an object from an external source such as an XML file. This makes our code more modular and easier to test.

Why do we need to Inject Dependency?

Because it has several benefits that improve the design, testability, and maintainability of your code base, dependency injection is an essential approach in software development. Instead of constructing the dependent instance inside the class, we can inject dependencies into a class using the design pattern known as dependency injection.

By using this pattern, an object or function can use a particular service without having to understand how to create it. Dependency injection’s key advantage is that it makes it possible for system objects to be loosely coupled. The goal of the design principle of loose coupling is to lessen the interdependence of system components. modifications to one object do not necessitate modifications to other objects when objects are loosely linked.

How Dependencies Are Injected?

Dependencies can be injected into a class in several ways: through constructor injection, setter injection, or method injection.

Constructor Injection:

  • Constructor injection is the fashion of statically declaring the necessary dependencies by supplying them as parameters to the class’s constructor.
  • The constructor hand of the type is included in the compendium process and is made available to the public.
  • It easily specifies that the Dependencies that the class requests in its constructor are needed.
  • When an object is formed, the dependencies are supplied to the object’s constructor. By doing this, the object is always initialized with all of its dependencies, and it’s simple to determine which dependencies the object requires.

public class GFGExample {

private final Dependency dependency;
public GFGExample(Dependency dependency) {
this.dependency = dependency;
}
public void doSomething() {
// Use the dependency here
}
}

Here is an Example of Constructor Injection:

Java




// Define the Adder interface
interface Adder {
    int add(int a, int b);
}
 
// Define the Calculator class, which has a
// dependency on the Adder interface
class Calculator {
    private Adder adder;
 
    // Constructor injection of the dependency
    public Calculator(Adder adder) { this.adder = adder; }
 
    // Method that uses the dependency
    // to perform addition
    public int add(int a, int b) { return adder.add(a, b); }
}
 
// Define a class that implements the
// Adder interface
class MyAdder implements Adder {
    @Override public int add(int a, int b) { return a + b; }
}
 
// Client code that creates an instance of
// the Calculator class
public class Main {
    public static void main(String[] args)
    {
 
        // Create an instance of the
        // Adder interface
        Adder adder = new MyAdder();
 
        // Create an instance of the Calculator
        // class and pass the dependency
        // (Adder interface)
        Calculator calculator = new Calculator(adder);
 
        // Use the Calculator instance to
        // perform addition
        int result = calculator.add(3, 4);
 
        // Print the result
        System.out.println("The result is: " + result);
    }
}


Output

The result is: 7

Setter Injection:

Setter injection is a dependency injection in which the spring framework injects the dependency object using the setter method. The call first goes to no argument constructor and then to the setter method. It does not create any new bean instance. Let’s see an example to inject dependency by the setter method.

public class MyClass {

private Dependency dependency;
public void setDependency(Dependency dependency) {

this.dependency = dependency;

}

// code comes here.
}

Here is an example of Setter Injection:

Java




// The Service Interface
public interface Service {
    String process();
}
 
// The Service Implementation
public class ServiceImpl implements Service {
    public String process()
    {
        return "Processing Service...";
    }
}
 
// The Controller
public class Controller {
    private Service service;
 
    // Setter Injection
    public void setService(Service service)
    {
        this.service = service;
    }
 
    public void performService()
    {
        System.out.println(service.process());
    }
}
 
// The Main Class
public class Main {
    public static void main(String[] args)
    {
        Controller controller = new Controller();
 
        // Instantiating ServiceImpl
        Service service = new ServiceImpl();
 
        // Injecting Service Dependency into Controller
        // using Setter Injection
        controller.setService(service);
 
        // Invoking Service using Controller
        controller.performService();
    }
}


In this instance, the Service class is dependent onto the Controller class. We inject the dependency from outside rather than explicitly constructing a Service class instance within the Controller class. We make a ServiceImpl class instance, which implements the Service interface. We then use the setService function to inject this instance into the Controller class.

We can adjust the Service interface’s implementation in this way without having to alter the Controller class. As a result, the code is easier to maintain and more adaptable.

Method Injection:

Using the method arguments rather than the constructor parameters, method injection provides a class’s dependencies.

In some situations where constructor injection might not be the ideal choice, this technique can be helpful. Constructor injection is generally advised, though, as it encourages improved code organization and immutability.

public class Controller {

public void doSomething() {

Service service = getService();

service.process();

}
// This method is where the Service dependency is injected
protected Service getService() {

return new ServiceImpl();

}
}

An example of method injection:

Java




// Car.java
public class Car {
    private Engine engine;
 
    public Car() {}
 
    public void setEngine(Engine engine)
    {
        this.engine = engine;
    }
 
    public void drive()
    {
        engine.start();
        System.out.println("Car is driving");
        engine.stop();
    }
}
 
// Engine.java
public class Engine {
    public void start()
    {
        System.out.println("Engine started");
    }
 
    public void stop()
    {
        System.out.println("Engine stopped");
    }
}
 
// Main.java
public class Main {
    public static void main(String[] args)
    {
        Car car = new Car();
        Engine engine = new Engine();
 
        car.setEngine(engine);
        car.drive();
    }
}


What is the best Way to inject Dependency?

The ideal technique to introduce dependency depends on the particular circumstances. However, constructor injection is typically regarded as the most effective method of injecting dependencies. This is so because it is straightforward, explicit, and simple to test. The dependencies are passed to the constructor of the object during constructor injection. As a result, the object will always be initialised with all of its dependents, and it will be clear which dependencies the object requires.

Constructor injection is the best way to inject dependencies because:

  • It makes sure that an object is generated in a valid state. By doing this, the probability of running into null reference exceptions later on in the application’s execution is decreased.
  • It makes dependencies explicit that means a class exposes all its class-level dependencies in its constructor.
  • It enables the use of immutable objects.

Advantages of Dependency Injection

Here are some advantages of dependency injection:

  • Dependency-driven increased modularity and reusability of code By separating components from their dependencies, injection encourages a clear separation of concerns. Because of this, developers can quickly alter or switch out parts of the application without compromising the overall functionality.
  • Enhanced testability, Using Dependency Injection makes it much simpler to test individual components since dependencies can be simply mocked or stubbed. This guarantees that it is possible to test the behaviour of individual components without also testing the behaviour of all of their dependencies.
  • Enhanced code maintainability is possible because Dependency Injection removes the requirement for components to handle the creation and management of dependencies, as this is done by an external system (such as a DI container). As a result, there is less duplication of code, improving maintainability.

Here are few instances where using DI can increase the quality of your code:

  • Injecting a database connection into your service layer through DI is possible. Your service layer will be simpler to test and manage as a result, regardless of the database implementation strategy.
  • You can use DI to add a logger to your controller layer. This will make it simpler for you to log errors and other events because you won’t have to worry about how to set up the logger.
  • An application configuration object can be introduced via DI. As a result, changing your application’s setup will be simple and have no impact on the remaining code.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads