SpringBoot Dependency Injection
Updated: Jul 29
by Siyavuya Viteka
What is Spring boot?
Spring boot is an open-source Java-based framework that is used to create microservices. It boasts the ability to create production-ready applications because it provides functionality that simplifies a lot of the configuration that would be done with creating your traditional apps, like automatically configuring 3rd-party libraries for your leisure.
What is dependency injection and why do we need it?
Dependency injection is the ability of one object, to provide the dependencies of another object. So, in programming, for one class to be able to use the functionalities of another class, an instance of the class has to be created every-time. This will cause our code to be very tightly-coupled, which is what dependency injection aims to address. So firstly, lets define the concepts of tight-coupling and loose-coupling.
Firstly, let’s start with tight-coupling. This concept basically means that, if one class knows too much about another class, they are tightly-coupled. In-fact if one class changes and affects the output of another class, or breaks the other class, then they are considered to be tightly-coupled, because if one of the classes changes, then the other class must change as well.
Let’s take for instance this practical example: Say for instance you wanted to change the engine of a car, from a petrol engine to a diesel one. That would mean you can no longer use petrol as fuel for your car, you would now have to switch to diesel as diesel engines can only operate using diesel. So, the engine and the fuel are tightly-coupled now you have to use diesel
Lets take for example this code snippet:
A class demo with a main method. This method then makes a new instance of the Car class and calls the method drive.
A class car that has a method drive that returns a string
The output of this program will obviously be : You can't drive to the beach. Buy fuel.
If the method 'drive' is altered in the car class, then it will directly affect what will be outputted because the drive method only has one implementation.
Loose coupling is the opposite of tight coupling. So, if one class doesn’t know the implementation of another class, then they are loosely coupled, because if something changes in the one class, it won’t affect the other class.
Still using the car as our example, imagine you and your friend are driving the car to the beach. On the way to the beach you suddenly feel tired, so you let your friend drive. Assuming your friend can drive and has a license, we can safely say that the car will continue operating till you reach your destination. The car and the driver are then loosely-coupled.
Lets take for example another code snippet:
This is a class 'CarImpl' that implements the car interface:
A Class VehicleImpl that also implements the car interface:
The car interface with the method, drive:
The output is: You cant drive to the beach. Buy fuel.
Even though the same method drive() is being called, the outputs are different because there are two different implementations for the drive method, one in the Vehicle class and the other in the CarImpl class. So, this illustrate loose-coupling as there can be many implementations of the car class and it won’t affect my main method. This is a basic example to illustrate the point.
Why use Dependency Injection?
So given our previous example, we can ascertain that loose-coupling is the better choice when developing systems as it allows for more code re-usability, increases flexibility and makes changes easier to implement. So, in essence, Spring boot uses dependency injection for these reasons. So, the work of injecting objects into other objects will be done by the assembler rather than by the objects themselves.
This helps with freeing up memory also, because when objects created and injected into another object they have to be instantiated. When dependency injection isn’t used, that would mean that there would be many instances of your multiple objects in memory during runtime. So, when the application is very large it could impact your applications performance. So, spring has put in place tools, to deal with that. Such as Beans and Autowiring.
What are beans?
In Spring, the objects that are used in your application and form its backbone, that are managed by the Spring IOC container are called beans. IOC container stands for inversion of things container. Simply put, this is the process of an object defining its dependencies but not creating them. The creation is left to the IOC container, and it will also manage those instances. So, a bean is an object that instantiated, assembled and then managed by the IOC container
“Autowired” is an annotation used by Spring boot, to inject collaborating beans into your bean. So basically, autowired is used to fetch the instance of the object that is already assembled, and hands it to you so that you can use it. To put this all into perspective, let’s look at a code snippet.
Here is a class called Human, that has a couple of methods such as eat. Notice that the inside the constructor, I print out “object created”. You can see a practical example of the spring IOC in action. If you created multiple instances of a class, you would expect “object created” to be logged multiple times. But if you create those instances and look at the console output, you’ll notice that “object created” is only printed once.
A controller to expose our service to the internet.
An implementation of the DependencyInjectionService interface:
The DependencyInjectionService interface:
the bean config file that has our beans in it.
Now as You can see in the implementation image, we can simply get an already created instance of the human class just by using the annotation @Autowired. This will look for the corresponding bean in your project that has already been created by The IOC container and injects it wherever you need, such as an implementation, in our case. Also, notice in the BeanConfig image, that is where we declare our bean using the @Configuration annotation for the class, and the @Bean annotation for the methods which will return the instances of the object we want. The bean will then be created and managed by the IOC container. Every Bean that we create in this config file, will only ever have one instance of itself running whilst our application is running. So, every time you use the @Autowired annotation, it will inject the same instance of the object where ever you use it, no matter how many classes use it.
The output of this program would be as follows:
Since the IOC container only creates one instance of the bean in your entire project, this can be very useful when it comes to very large applications that can consume a lot of memory with many instances running. Spring has brought us dependency injection and simplified all of this for us.