Design Pattern - Dependency Injection

Card Puncher Data Processing

About

Dependency injection is:

An injection is the passing of a Dependency (ie a service via a variable storing the client's state) to a dependent object (a client).

The control of the flow (dependency construction flow) is reversed because the component does not control the construction of its dependency. This is why dependency injection is also known as Inversion of Control. For purists, dependency injection is only the component assembly part (Not the configuration and lifecycle part) of the Inversion of Control design principle.

Dependency injection is a software design pattern that implements inversion of control and allows a program design to follow the dependency inversion principle and single responsibility principles.

It's a means for obtaining objects (components, bean) where they get their dependencies through:

  • their constructors arguments,
  • methods,
  • arguments to a factory method,
  • properties that are set on the object instance after it is constructed
  • or directly into fields.

Before building an object, its dependencies need to be build. And as each dependency is also itself an object, building an object is really building an object graph.

Example

For instance, you can inject a bean into a Servlet by using this annotation.

@EJB myBean ejb;

Purpose

  • The purpose of Dependency Injection is to reduce coupling in your application to make it more flexible and easier to test, ensure that components are loosely coupled.
  • The core principle is to separate behavior from dependency resolution (the same than composition)
  • Objects don't have hard coded dependencies. If you need to change the implementation of a dependency, all you have to do is Inject a different type of Object.
  • Dependency injection is beneficial to most nontrivial applications.

Usage

Inject Service

Dependency injection is often used to inject services, like a logger or a translator.

Test Mock

The object does not look up its dependencies and does not know the location or class of the dependencies. As a result, your classes become easier to test, particularly when the dependencies are on interfaces or abstract base classes, which allow for stub or mock implementations to be used in unit tests.

Example

Manually

The typical pattern is to construct the graph and then call one method on one object to send the flow of control into the object graph.

public static void main(String[] args) throws IOException {

    // Construction code. 
    Greeter greeter = new Greeter(System.out); // This may be many lines that connect many objects
    
    // Behavior code.
    greeter.greet(); // This is one call to one method on one object in the object graph
}

class Greeter {
    public void greet() {
        this.out.println("Hello world!");
    }
    public Greeter(PrintStream out) {
        this.out = out;
    }
    private PrintStream out;
}

Injector

Building object graphs by hand is labour intensive, error prone, and makes testing difficult. Instead, a container or dependency injector can build the object graph for you.

Type

Ways to specify the injection of dependencies into components

How an object can receive a reference to an external module:

  • constructor_injection: the dependencies are provided through a class constructor.
  • setter_injection: the client exposes a setter method that the injector uses to inject the dependency.
  • interface_injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.
  • annotated_injection Methods are marked with an annotation to indicate that they should be used for injecting dependencies

The different injector implementations:

  • factories,
  • service locators,
  • dependency injection containers - It's a library that takes care of keeping dependencies in a registry, instantiating them on demand, and making them configurable

Without Injection

  • An example without dependency injection
public class Client {

    // Internal reference to the service used by this client
    private Service service;

    // Constructor
    Client() {
        // Specify a specific implementation in the constructor instead of using dependency injection
        service = new ServiceExample();
    }

    // Method within this client that uses the services
    public String greet() {
        return "Hello " + service.getName();
    }
}

Constructor Injection

constructor

Constructor Injection is a Dependency Injection variant where a component gets all its dependencies at construction time:

  • via its signature
  • or field/method injection

Doc

public class Client {

    // Internal reference to the service used by this client
    private Service service;

    // Constructor
    Client(Service service) {
        // The service is given through a constructor argument
        this.service = service;
    }

    // Method within this client that uses the services
    public String greet() {
        return "Hello " + service.getName();
    }
}

Injection Point:

  • Annotation:
    • Method: Methods are marked with an annotation to indicate that they should be used for injecting dependencies
    • Field: Fields are marked with an annotation to indicate that they should be injected into
  • Named:
    • Named Field - Fields of a certain name should be injected into
    • Named Method - If method names match other component names, injection happens

Setter injection

Setter Injection is a Dependency Injection variant where an object gets all dependencies via setter methods.

the client exposes a setter method that the injector uses to inject the dependency.

Setter Injection is where the container or embedder hands dependencies to a component via setter methods after instantiation.

Setter Injection is idiomatic of the Spring Framework

The disadvantage of Setter Injection there is the possibility to forget to inject some of the dependencies, and the component fail later because of that unset dependency.

This method requires the client to provide a setter method for the dependency.

public class Client {

    // Internal reference to the service used by this client
    private Service service;

    // Constructor
    Client() {
    }

    // Setter method
    public void setService(Service service) {
        // Save the reference to the passed-in service inside this client
        this.service = service;
    }

    // Method within this client that uses the services
    public String greet() {
        return "Hello " + service.getName();
    }
}

Doc: http://picocontainer.com/setter-injection.html

Interface injection

The interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.

The interface define just how the injector should talk to the client when injecting dependencies.

  • Service setter interface.
public interface ServiceSetter {
    public void setService(Service service);
}
  • Client class
public class Client implements ServiceSetter {
    // Internal reference to the service used by this client.
    private Service service;

    // Set the service that this client is to use.
    @Override
    public void setService(Service service) {
        this.service = service;
    }
}

Framework / Library

See Dependency - Injector

Documentation / Reference





Discover More
Card Puncher Data Processing
Dependency Inversion Principle

The concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions whereas the dependency injection is the decoupling between type dependency dependency...
Java Conceptuel Diagram
J2EE - Session Bean

A session bean encapsulates business logic that can be invoked programmatically by a client over local, remote, or web service client views. To access an application that is deployed on the server, the...
Java Conceptuel Diagram
Java - Annotations

Since Java version 1.5. An annotation is an element of the java programming language (modifier or Metadata tag) that can be associated with: Java classes, interfaces, constructors, methods,...
Java Conceptuel Diagram
Java - Dependency Injection (DI)

Dependency injection in Java. This page is injection of a java dependency in a class. Google: Dagger is is dependency injection at compile time while Guice is at runtime ...
Data System Architecture
Logical Data Modeling - Dependency (Coupling)

A dependency is a Relationship that signifies that a entity requires other entity for their specification or implementation. This means that the complete semantics of the client (the dependent) are either...
React - Dependency Injection

in React (via parent/children) Interface: only via Typescript
Card Puncher Data Processing
Type - Dependency Resolve (Dependency Resolution)

dependency wiring Wiring everything together is a tedious part of application development. The process of finding an instance of a type dependency to use atrun time is known as resolving the dependency...



Share this page:
Follow us:
Task Runner