Spring Loose coupling + Basic Terminlogies
Tags: java, spring
Published: 2023-02-03 04:23:41

In my previous article, **[Tight Coupling and Loose Coupling in Java](https://dev.to/dr0nser/tight-coupling-and-loose-coupling-implementation-in-java-5ff1)**, 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](https://dev.to/dr0nser/tight-coupling-and-loose-coupling-implementation-in-java-5ff1)** 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:
1. `@Component`: Hey spring, this is a component and you need to manage its lifecycle.
2. `@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
```java
// 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:
1. In our `Smartphone` class, we didn't create any object manually. Instead, we used `getBean()` to get an instance of the `Instagram` class.
2. We also see than when we are calling the `instagramBean.run()` method, the private variable `camera` is able to access `click()` and `record()` methods without being instantiated. Since, we have used `@Autowired`, spring automatically finds the class `MyPhoneCamera` using the `Camera` type and autowires an object of it to the `private 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:
1. Annotations:
	1. `@Component`
	2. `@Autowired`
2. Terminologies:
	1. Beans
	2. IoC Container
	3. Application Context
	4. Dependency Injection
	5. Loose coupling with implementation