Dependency Injection Example Using Spring

15 Comments

Last Updated on May 27, 2019 by Simanta

Dependency Injection

The Spring Framework is literally built around the concept of Dependency Injection. In this post, we’ll take a look at a simple example of Dependency Injection using the Spring Framework.

If you want a deeper dive on Dependency Injection and how it works in conjunction with Inversion of Control in the Spring Framework, sign up for my free Introduction to Spring tutorial at the bottom of this post.

Dependency Injection Example

In this blog post, I will take a realistic example of having a web controller and a service. In practice, the controller would be responsible for managing requests from the web, and the service would interact with the persistence layer.

Domain

Our service will return a domain class. In this example, our controller will return a simple list of products.

Product Class

package guru.springframework.domain;

/**
 * Created by jt on 3/27/15.
 */
public class Product {
    private String description;

    public Product(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

 

Service Layer

Ideally, when you are coding for Dependency Injection, you will want to code to an interface. This will allow you easily utilize polymorphism and implement different concrete implementations. When coding for the use of dependency injection, coding to an interface also complies with the Interface Segregation Principle of the SOLID principles of Object Oriented Programming.

A common example would be to have the implementation you will use in your production code, and then a mock implementation for unit testing your code. This is the power of dependency injection. It allows you to change the behavior of your application through configuration changes over code changes. For example with persistence, you might be injecting a mock for unit testing, a H2 database for local development and CI builds, and then a Oracle implementation when your code is running in production. When developing enterprise class applications, dependency injection gives you a tremendous amount of versatility.

Interface

Example Interface:

package guru.springframework.services;

import guru.springframework.domain.Product;

import java.util.List;

/**
 * Created by jt on 3/27/15.
 */
public interface ProductService {

    List<Product> listProducts();
}

 

Implementation

Here is the implementation of the service. This is just a simple implementation which returns a list of Product domain POJOs, which is sufficient for this example. Naturally, in a real example, this implementation would be interacting with the database or possibly a web service.

I’ve annotated the class with @Service , this tells Spring this class is a Spring Bean to be managed by the Spring Framework. This step is critical, Spring will not detect this class as a Spring Bean without this annotation. Alternatively, you could explicitly define the bean in a Spring configuration file.

package guru.springframework.services;

import guru.springframework.domain.Product;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by jt on 3/27/15.
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Override
    public List<Product> listProducts() {
        ArrayList<Product> products = new ArrayList<Product>(2);
        products.add(new Product("Product 1 description"));
        products.add(new Product("Product 2 description"));
        return products;
    }
}

 

Controller

We have a simple controller to return a list of Products to our view layer. In this example, I’m using setter based Dependency Injection.   First, I’ve defined property in our example controller using the Interface type, not the concrete class. This allows any class to be injected which implements the specified interface.  On the setter, you see the @Autowired  annotation. This directs Spring to inject a Spring managed bean into this class.  Our controller class is also annotated with the @Controller  annotation. This marks the class as a Spring Managed bean. Without this annotation, Spring will not bring this class into the context, and will not inject an instance of the service into the class.

package guru.springframework.controllers;

import guru.springframework.domain.Product;
import guru.springframework.services.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.util.List;

/**
 * Created by jt on 3/27/15.
 */
@Controller
public class MyController {

    private ProductService productService;

    @Autowired
    public void setProductService(ProductService productService) {
        this.productService = productService;
    }

    public List<Product> getProducts(){
        return productService.listProducts();
    }

}

 

Running the Example

We’ll use Spring Boot to run our example. Spring Boot will help bring up the Spring context for running our example. Spring Boot does automate a lot of common tasks for us. For example, it will automatically do a component scan in the package the class is running in.

Example Execution Code

For our example, we need to tell Spring where our components are located. We use the @ComponentScan  annotation. By using this annotation Spring will scan the specified package for Spring components (aka Spring managed beans).

In our main method, we get the Spring Context, then request from the context an instance of our controller bean. Spring will give us an instance of the controller. Spring will perform the Dependency Injection for us, and inject the dependent components into the object returned to us.

It is important to remember, the Spring Context is returning to us Spring Managed beans. This means Spring will be managing the dependency injection for us. If for some reason, Spring cannot fulfill a dependency, it will fail to startup. You will see in the stack trace information about the missing dependencies.

package diexample;

import guru.springframework.controllers.MyController;
import guru.springframework.domain.Product;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.List;

@SpringBootApplication
@ComponentScan("guru.springframework")
public class DiExampleApplication {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DiExampleApplication.class, args);
        MyController controller = (MyController) ctx.getBean("myController");
        List<Product> products = controller.getProducts();

        for(Product product : products){
            System.out.println(product.getDescription());
        }
    }
}

 

Console Output

When you run the above example, you will see the following output in the console.  Note in the console output, you see our two product descriptions, which proves that Spring did in fact wire our controller correctly. If Spring did not, our code would have failed on a null pointer error.

   .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.2.RELEASE)

2015-03-27 10:28:21.016  INFO 64108 --- [           main] diexample.DiExampleApplication           : Starting DiExampleApplication on Johns-MacBook-Pro.local with PID 64108 (/Users/jt/src/springframework.guru/blog/di-example/target/classes started by jt in /Users/jt/src/springframework.guru/blog/di-example)
2015-03-27 10:28:21.115  INFO 64108 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3e57cd70: startup date [Fri Mar 27 10:28:21 EDT 2015]; root of context hierarchy
2015-03-27 10:28:22.107  INFO 64108 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-03-27 10:28:22.121  INFO 64108 --- [           main] diexample.DiExampleApplication           : Started DiExampleApplication in 1.606 seconds (JVM running for 2.134)
Product 1 description
Product 2 description
2015-03-27 10:28:22.122  INFO 64108 --- [       Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3e57cd70: startup date [Fri Mar 27 10:28:21 EDT 2015]; root of context hierarchy
2015-03-27 10:28:22.123  INFO 64108 --- [       Thread-1] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Video Code Review

Below is a brief video where I review the code used in this example.

Conclusion

In this post we demonstrated a very basic example of Spring Dependency Injection using the Spring Framework. I hope you can see how simple Spring makes Dependency Injection. If you wish to learn more about the Spring Framework and Dependency Injection, checkout my free Introduction to Spring Tutorial!

Free Introduction to Spring Tutorial

Are you new to the Spring Framework? Checkout my Free Introduction to Spring Online Tutorial.

Get The Code

A complete working example of the code for this post is available on github.

The source code for this post is available on github. You can download it here.

About jt

    You May Also Like

    15 comments on “Dependency Injection Example Using Spring

    1. February 12, 2016 at 9:00 am

      What if you want to have more than one class injected into the dependent class depending on other parameters, during the same run. Say you have a Person interface and some times you want to use Male and sometimes you want to use Female?
      How do you use Spring for that?

      Reply
      • February 12, 2016 at 9:04 am

        Sounds like a use case for profiles.

        Reply
    2. February 12, 2016 at 10:03 am

      Not as I understand them. Isn’t one profile used for an entire run? I want to be able to switch between classes implementing the same interface during one run. So one time I will inject a Male object and the next, maybe, a Female object.

      Reply
      • March 2, 2016 at 7:11 am

        Yes, Spring Profiles control how things are wired at run time. You’re describing more of a use case for a builder pattern – which will construct the object based on the runtime needs.

        Reply
    3. March 1, 2016 at 10:00 pm

      I dont think its possible, at run time you can have only one definition. I believe injection happens only at time when spring application context created based on that it injects – not sure we can change it easily without reloading application context and all….hmmm I dont think we can inject diff implementations at run time with elegant way..let me know if you found solution.

      Reply
      • March 2, 2016 at 7:09 am

        Not really a use case for DI in a traditional sense. More of a use case for a GOF builder pattern.

        Reply
    4. July 21, 2016 at 8:41 am

      Hello,
      Is it possible to dynamically inject a specific instance of a class at runtime?
      Background, I have a an abstract class MetricManager implementing IMetricManager interface. I have 2 other classes that extend MetricManger, TypeAManager and TypeBManager.

      Based on some user defined inputs at startup I need to instantiate either TypeA or TypeB at runtime.

      Is this possible?

      thanks,
      mbeddedsoft

      Reply
      • July 21, 2016 at 9:19 am

        Yes, you can achieve that functionality using Spring profiles.

        Reply
    5. December 7, 2016 at 2:05 am

      Hello
      Is it OK for injecting Service instance into Controller?
      Does it have low performance when Service accesses database? The other users have to wait?
      Or just I have to create or inject new Service when method is invoked?

      thanks,
      hansheng

      Reply
      • December 7, 2016 at 5:29 am

        Generally, the injection occurs when the application is started. So, at runtime there is no overhead of object creation.

        Reply

    Leave a Reply

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

    This site uses Akismet to reduce spam. Learn how your comment data is processed.