Spring Loose coupling + Basic Terminlogies
In my previous article, Tight Coupling and Loose Coupling in Java, we had implemented loose coupling using an interface. If you are new to the concept of implementing loose coupling then I would recommend you to read the above mentioned article before you proceed with this. With that sorted, let's start with Loose coupling in Spring.
Inversion of Control
The problem with the approach I had used to implement loose coupling in Tight Coupling and Loose Coupling in Java is that it is not efficient for enterprise applications. An enterprise application might have throusands of classes and objects and manually creating and managing objects for them is very tedious. So, we give this responsibility to spring. Sping creates and manages the instances of the classes on our behalf. This giving of control to spring to manage classes and objects in called Inversion of Control.
Annotations and Terminologies
To allow Spring to take control of classes there are 2 annotations we need to be familiar with. Annotations give meaning to a piece of code. It allows Spring to better understand our goal. The 2 annotations and what message they convey to Spring are as follows:
@Component
: Hey spring, this is a component and you need to manage its lifecycle.@Autowired
: Hey spring, there is already a component of this type, so go and find it. Once you find it, autowire it to the current object. Now, we can tell spring to manage a component lifecycle using@Component
and allow Spring to identify and create an object of a component using@Autowired
.
But there should be a place where the objects should be managed right? Yes, there is an interface called ApplicationContext
which provides the functionalities to manage the object lifecycle. This Application Context represents the IoC Container in Spring. IoC Container stores and manages the instances of the classes and the instances created are called Beans.
To demonstrate all of the things we learned so far, let's see a real life example. Consider our smartphone, we have a camera in our smartphone, that same camera is used by various apps like Instagram, Facebook, etc. Now, let's to implement the scenario where Instagram will be using our camera.
Loose coupling Implementation in Spring
// consider this the base camera architecture giving features like 12MP with OIS, etc.
public interface Camera {
public void click();
public void record();
}
// We use the camera architecture to create our camera software for our phone
@Component
public class MyPhoneCamera implements Camera {
@Override
public void click() {
System.out.println("Picture clicked!");
}
@Override
public void record() {
System.out.println("Recording video...");
}
}
// Instagram will interact with the Mobile OS like Android, iOS, etc. to use the camera and provide its own features like filters, stickers, etc. but here we will see only the basics
@Component
public class Instagram {
@Autowired
private Camera camera;
public void run() {
int choice = 0;
Scanner sc = new Scanner(System.in);
outerloop:
while (true) {
System.out.println("1. Click picture\n2. Record Video\n3. Exit Instagram\nEnter choice: ");
choice = sc.nextInt();
switch (choice) {
case 1: camera.click();break;
case 2: camera.record();break;
case 3: System.out.println("Instagram closed"); break outerloop;
default: System.out.println("Please enter correct choice!");
}
}
}
}
// finally our smartphone from where we run the instagram app
@SpringBootApplication
public class Smartphone {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Smartphone.class, args);
Instagram instagramBean = applicationContext.getBean(Instagram.class);
instagramBean.run();
}
}
So, some observations we can see from the above implementation:
- In our
Smartphone
class, we didn't create any object manually. Instead, we usedgetBean()
to get an instance of theInstagram
class. - We also see than when we are calling the
instagramBean.run()
method, the private variablecamera
is able to accessclick()
andrecord()
methods without being instantiated. Since, we have used@Autowired
, spring automatically finds the classMyPhoneCamera
using theCamera
type and autowires an object of it to theprivate Camera camera
variable. This method of injecting an object to another object is called Dependency Injection in Spring.
Now, you may have a question what does all this demonstrate? Why are we using the annotations?
The answer is to create Loosely-coupled systems. We can change MyPhoneCamera
implementation and the application will run fine(till the architecture is unchanged i.e. the methods of the interface remains same). Other applications can also use our phone camera i.e. MyPhoneCamera
and create its own features.
Summary
We learned:
- Annotations:
@Component
@Autowired
- Terminologies:
- Beans
- IoC Container
- Application Context
- Dependency Injection
- Loose coupling with implementation