DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. IoC vs. DI

IoC vs. DI

Some people use the terms Inversion of Control and Dependency Injection interchangeably. Let's see how they're different and how they can work together.

Francisco Alvarez user avatar by
Francisco Alvarez
CORE ·
Dec. 27, 17 · Tutorial
Like (106)
Save
Tweet
Share
138.71K Views

Join the DZone community and get the full member experience.

Join For Free

Lately, I have been interviewing candidates for a developer role and realized how much confusion there is, still, around the concepts of Inversion of Control and Dependency Injection. The majority of people use both terms interchangeably. Probably, the confusion derives from the heavy use of those concepts in Spring, where Inversion of Control is used to enable Dependency Injection.

This post aims to explain both ideas in a simple way. 

Inversion of Control

Basic Concepts

Here is an informal definition of IoC: “IoC is when you have someone else create objects for you.” So instead of writing “new MyObject” in your code, the object is created by someone else. This ‘someone else’ is normally referred to as an IoC container.

This simple explanation illustrates some very important ideas:

  1. It is called IoC because control of the object is inverted. It is not the programmer, but someone else who controls the object.
  2. IoC is relative in the sense that it only applies to some objects of the application. So there may be IoC for some objects, whereas others are under the direct control of the programmer.

Apart from Spring, there are other examples of IoC like Java Servlets and Akka Actors.

The Details

Let’s delve a little more into the definition of IoC. IoC is much more than object creation: a Spring Context or a Servlet Container not only create objects, but manage their entire lifecycle. That includes creating objects, destroying them, and invoking certain methods of the object at different stages of its lifecycle. These methods are often described as callbacks. Notice again the terminology: methods invoked by the container are callbacks, as opposed to the direct calls that programmers make on their own code.

All the IoC containers previously mentioned implement some kind of lifecycle: Spring Bean Lifecycle, Servlet Lifecycle, and Akka Actor Lifecycle.

Another thing to consider is that, although programmers relinquish their control on the objects, they still need to define the templates used by the IoC container to create said objects.

For instance, in Spring, classes are annotated with @Service or @Component (among many others) to indicate that the Spring Container is to manage the instances of those classes (it is also possible to use XML configuration instead of annotations). Spring-managed objects, as you likely know, are called Beans.

In a Servlet application, any class implementing the Servlet interface will be managed by the Servlet Container.

In an Akka application, the IoC container is called ActorSystem and the managed objects are instances of classes extending the trait Actor and created through configuration objects called Props.

Here is a quick summary of the ideas discussed so far:

  1. IoC containers control and manage the lifecycle of some objects: creation, destruction, and callback invocations.
  2. The programmer must identify the classes whose instances are to be managed by the IoC container. There are several ways to do this: with annotations, by extending some specific classes, using external configuration.
  3. The programmer can influence, to some extent, the way the objects are managed by the IoC container. Normally, this is achieved by overriding the default behavior of the object callbacks.
IoC Container Managed Object Name Managed Objects Definition
Spring Container Bean Classes defined with annotations/XML configuration
Servlet Container Servlet Classes implementing interface Servlet
Actor System Actor Classes extending trait Actor


So far, we have managed to explain IoC without needing to talk about Dependency Injection. 

Dependency Injection

Dependency Injection has become one of the cornerstones of modern software engineering, as it is fundamental to allow proper testing. To put it simply, having DI is the opposite to having hardcoded dependencies.

//Hardcoded dependency
public class MyClass { 
    private MyDependency myDependency = new MyDependency(); 
}
//Injected dependency
public class MyClass { 
    private MyDependency myDependency;

    public MyClass(MyDependency myDependency){
        this.myDependency = myDependency;
    }
}

 

A dependency can be injected in several ways, like a parameter in the constructor or through a “set” method.

As important as DI is, there is a downside to its use, namely: management of dependencies is inconvenient. Let’s take a look at an example: MyClass1 depends on MyClass2, that in turns depends upon MyClass3:

public class MyClass3 {
    public void doSomething(){}
}
//MyClass2 depends on MyClass3
public class MyClass2 {
    private MyClass3 myClass3;

    public MyClass2(MyClass3 myClass3){
        this.myClass3 = myClass3;
    }

    public void doSomething(){
        myClass3.doSomething();
    }
}
//MyClass1 depends on MyClass2
public class MyClass1 {
    private MyClass2 myClass2;

    public MyClass1(MyClass2 myClass2){
        this.myClass2 = myClass2;
    }

    public void doSomething(){
        myClass2.doSomething();
    }
}
public class Main {

    public static void main(String[] args) {

        //All dependencies need to be managed by the developer
        MyClass3 myClass3 = new MyClass3();
        MyClass2 myClass2 = new MyClass2(myClass3);
        MyClass1 myClass1 = new MyClass1(myClass2);

        myClass1.doSomething();
    }
}

 

Now, let’s assume that further down the line, MyClass2 needs a new dependency: MyClass4. We need to make changes to account for this new dependency:

public class MyClass2 {
    private MyClass3 myClass3;
    private MyClass4 myClass4;

    public MyClass2(MyClass3 myClass3, MyClass4 myClass4){
        this.myClass3 = myClass3;
        this.myClass4 = myClass4;
    }

    public void doSomething(){
        myClass3.doSomething();
        myClass4.doSomething();
    }
}
public class Main {

    public static void main(String[] args) {

        MyClass4 myClass4 = new MyClass4();
        MyClass3 myClass3 = new MyClass3();
        MyClass2 myClass2 = new MyClass2(myClass3, myClass4);
        MyClass1 myClass1 = new MyClass1(myClass2);

        myClass1.doSomething();
    }
}

 

Although the situation described in this example is not too bad, real-life applications can have hundreds of dependencies scattered all across the codebase whose creation and management would need to be centralized like in the above example.

Inversion of Control and Dependency Injection Playing Together

We just discussed the issue of managing hundreds of dependencies in a real-life application, possibly with very complicated dependency graphs.

So here is where IoC comes to the rescue. With IoC, the dependencies are managed by the container, and the programmer is relieved of that burden.

Using annotations like @Autowired, the container is asked to inject a dependency where it is needed, and the programmers do not need to create/manage those dependencies by themselves.

public class MyClass1 {

    @Autowired
    private MyClass2 myClass2;

    public void doSomething(){
        myClass2.doSomething();
    }
}
public class MyClass2 {

    @Autowired
    private MyClass3 myClass3;
    @Autowired
    private MyClass4 myClass4;

    public void doSomething(){
        myClass3.doSomething();
        myClass4.doSomething();
    }
}

 

Conclusion

We have presented Inversion of Control and Dependency Injection as separate concepts and justified how in some situations both concepts can be combined to provide superior solutions.

Dependency injection Object (computer science) Inversion of control Container Spring Framework Programmer (hardware) Concept (generic programming) application Akka (toolkit)

Published at DZone with permission of Francisco Alvarez, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Choose the Right Streaming Database
  • Solving the Kubernetes Security Puzzle
  • A Gentle Introduction to Kubernetes
  • Testing Level Dynamics: Achieving Confidence From Testing

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: