What is the best way to inject Dependency in Java?
Last Updated :
23 Jul, 2025
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);
}
}
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.
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem