Latest News

Implement Your own Dependency Injection – DZone Java

Overview

This article will guide you to understand and build a lightweight java application using your own Dependency Injection implementation.

Dependency Injection…DI… Inversion Of Control…IoC, I guess you might have heard these names so many times during your routine or especially interview preparation time that you wonder what exactly it is.

But if you really want to understand how it works internally, then continue reading here.

So, Dependency Injection?

Dependency injection is a technique in which instance variables (i.e., dependencies) of an object got created and assigned by the framework.

Any class and instance variables need to add annotations predefined by the framework to use the DI feature.

Commonly Used Terms in the DI:

  • The client is the Object containing dependencies.
  • Service is each dependency inside the Client and Object creation and to inject into the Client is done by the framework.
  • The injector is the code that passes or injects the service into the client object.
  • Interfaces that define how the client may use the services.
  • Injection refers to the passing of a dependency (a service) into the object (a client), also referred to as auto-wire.

So, Inversion Of Control?

In short, “Don’t call us; we’ll call you.”

  • It is more general than dependency injection. Dependency injection one of the approaches to implement the IoC.
  • It decouples the execution of a task from implementation.
  • It focuses a module on the task it is designed for.
  • It free modules from assumptions about how other systems do what they do and instead rely on contracts.
  • It prevents side effects when replacing a module.

Class Diagram for DI Design Pattern:

accountservice

In the above class diagram, the Client class that requires UserService and AccountService objects does not instantiate the UserServiceImpl and AccountServiceImpl classes directly.

Instead, an Injector class creates the objects and injects them into the Client, making the Client independent of how the objects are created.

Types of Dependency Injection

  • Constructor injection

The dependencies are provided through a client’s class constructor.

  • Setter injection

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

  • Interface injection 

The dependency’s interface provides an injector method that will inject the dependency into any client passed to it.

Clients must implement ensure the respective class implements this interface before use as a service.

How it Works — Explanation With the Code Example.

As described above, DI has to provide predefined annotations, which can be added during the Client class and Service variables inside a Client.

For a better explanation, go through the below code snippets.

User-defined annotations Dependency Injection implementation.

CustomComponent.java

CustomAutowired.java 

CustomQualifier.java

Service Interfaces as Example:

UserService.java

public interface UserService

{ String getUserName();

}

AccountService .java

public interface AccountService

{ Long getAccountNumber(String userName);

}

Service classes, as an example, implement the above interfaces:

UserServiceImpl.java

import com.useraccount.annotations.CustomComponent;

import com.useraccount.services.UserService;

AccountServiceImpl.java

import com.useraccount.annotations.CustomComponent;

import com.useraccount.services.AccountService;

Client Class as an example, using the DI features with the help of user-defined annotations.

UserAccountClientComponent.java

import com.useraccount.annotations.*;

import com.useraccount.services.*;

Injector: it plays a major role in the DI framework to create instances of all clients and auto-wire instances for each service in Client classes.

Steps:

1. Scan all the clients under the root package and all sub-packages

2. Create an instance of the client class.

3. Scan all the services using in the client class (member variables, constructor parameters, method parameters)

4. Scan for all services declared inside the service itself (nested dependencies), recursively

5. Create an instance for each service returned by step3 and step4

6. Autowire: Inject (i.e., initialize) each service with instance created at step5

7. Create Map all the client classes

8. Expose API to get the getBean(Class class)/getService(Class class).

9. Validate if there are multiple implementations of the interface or there is no implementation

10. Handle Qualifier for services or autofire by type in case of multiple implementations.

CustomInjector.java

Conclusion

This article should give a clear understanding just of how DI or autowire dependencies work.

With the implementation of your own DI framework, you don’t need heavy frameworks like SpringBoot. You are really not using other heavy features in your application, e.g., application.yml configuration or Bean Lifecycle Management methods and much more heavy stuff.

You can do many things that are not mentioned here by adding more user-defined annotations for various purposes, e.g., bean scopes singleton, prototype, request, session, global-session, and many more similar features to Spring framework provides.

Thanks for taking the time to read this article, and I hope this gives a clear picture of how to use and internal working of Dependency Injection.

Topics:

overview,
java,
tutorial,
dependecy injection,
di,
inversion

Opinions expressed by DZone contributors are their own.

Read More

Show More

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button

Adblock Detected

Please consider supporting us by disabling your ad blocker