🌿 Spring IOC & DI

GunhoΒ·2024λ…„ 11μ›” 10일
1

Object Oriented Programming (OOP) & Java

λͺ©λ‘ 보기
16/29

🌿 Spring IOC & DI

🌿 Spring IoC & DI are the foundations of Spring framework.

Spring Doc Available at here


IoC (Inversion of Control) is a software principle where the overall management of the object lifecycle is handled by a framework than a developer. In Spring, it is the Spring IoC container that instantiates, configures, and assembles the Spring object termed as Spring Beans.

Following, IoC, developers can better focus on implementing business logic than managing the Spring Bean objects and hence increase:

  • βš™οΈ code maintainability

  • 🌭 code extensibility

DI (Dependency Injection) is a pattern of IoC in which it strictly refers to a mechanism where dependencies required to create Spring Bean objects are injected externally perhaps by Spring IoC Container.

DI often results in:

  • πŸ’ low coupling

    • followed by the Dependency Inversion Principle
  • πŸ¦‘ code flexibility

  • 🧐 testability

πŸ’‰ Spring DI

Spring DI can be achieved mostly by the following approaches:

  • 🧱 Constructor Dependency Injection
  • πŸŽ„ Setter Dependency Injection
  • 🚎 @Autowired
  • πŸ“Ÿ XML

the above methods will be discussed with the given code snippet.

Tire classes

// Tire Interface
public interface Tire {
	String getBrand();
}

// KoreanTire Class
public KoreanTire implements Tire {
	@Override
    public String getBrand() {
    	return "KoreanTire";
    }
}

// AmericanTire Class
public AmericanTire implements Tire {
	@Override
    public String getBrand() {
    	return "AmericanTire";
    }
}

🧱 Constructor Dependency Injection

🧱 Constructor Dependency Injection is a mechanism where the dependencies are injected by the constructors.

Below code snippet can be a good example of the Constructor Dependency Injection.

Car class

public class Car {
	private Tire tire;
    
    public Car(Tire tire) {
    	this.tire = tire;
    }
    
    public void checkTire() {
    	System.out.println(tire.getBrand());
    }
}

and given the above code, dependencies can be injected as below at the client level. Similarly, under the context of Spring framework, the below DI is automatically handled by Spring IoC Container.

Client

public class Client {
	public static void main(String[] args) {
    	Tire koreanTire = new KoreanTire();
        Tire americanTire = new AmericanTire();
        
        Car car1 = new Car(koreanTire);
        Car car2 = new Car(americanTire);
        
        car1.checkTire(); // "KoreanTire"
        car2.checkTire(); // "AmericanTire"
    }
}

πŸŽ„ Setter Dependency Injection

πŸŽ„ Constructor Dependency Injection is a mechanism where the dependencies are injected by the setters.

Setter Dependency Injection can be implemented like the below code snippet.

Car class

public class Car {
	private Tire tire;
    
    public Car() {
    }
    
    public void setTire(Tire tire) {
    	this.tire = tire;
    }
    
    public void checkTire() {
    	System.out.println(tire.getBrand());
    }
}

given the above code, setters() can be invoked and dependencies then can be injected.

Client

public class Client {
	public static void main(String[] args) {
    	Tire koreanTire = new KoreanTire();
        Tire americanTire = new AmericanTire();
        
        Car car1 = new Car();
        Car car2 = new Car();
        
        car1.setTire(koreanTire);
        car2.setTire(americanTire);
        
        car1.checkTire(); // "KoreanTire"
        car2.checkTire(); // "AmericanTire"
    }
}

🚎 @Autowired

🚎 @Autowired is a Spring dependent feature where the Spring automatically injects dependencies on the @Autowired declared code snippets.

@Autowired can be applied at constructors, methods, and fields where the earlier two correspond to the Constructor DI and Setter DI. Over the @Autowired declared fields, however, Spring internally finds relevant Spring Bean object and processes DI.

@Autowired (Constructor)

// Constructor
public class Example {
	private Needed needed;
    
    @Autowired
    public Example(Needed needed) {
    	this.needed = needed;
    }
}

@Autowired (Setter or Method)

// Constructor
public class Example {
	private Needed needed;
    
    public Example() {
    }
    
    // Setter
    @Autowired
    public void setNeeded(Needed needed) {
    	this.needed = needed;
    }
    
    // Method
    @Autowired
    public void setNecessary(Needed needed) {
    	this.needed = needed;
    }
}

@Autowired (Field)

// Constructor
public class Example {

	@Autowired
	private Needed needed;    
}

Although, @Autowired provides Spring automated DI, implementing DI via @Autowired is not desirable if considering its resulting difficulties in unit testing as there is no way to inject required dependencies in the context of testing environment. Hence, Constructor DI and Setter DI would be better DI practices than the @Autowired field DI.

Over Constructor DI and Setter DI, following Setter DI's capability to modify dependencies, it is often not preferred in the industry standards, implying Constructor DI for non-modifying dependencies is the best DI practice with a final keyword:

@Autowired (Constructor & final)

// Constructor
public class Example {
	private final Needed needed;
    
    @Autowired
    public Example(Needed needed) {
    	this.needed = needed;
    }
}

πŸ“Ÿ XML

πŸ“Ÿ XML is a legacy approach for Spring DI, in which a developer externally specifies all the DI configurations in the XML files by providing id, and property references.

services.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- services -->

	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
		<property name="accountDao" ref="accountDao"/>
		<property name="itemDao" ref="itemDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for services go here -->

</beans>

daos.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="accountDao"
		class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for data access objects go here -->

</beans>

🫷Autowiring Priorities

DI in Spring has priorities and rules, where failing to qualify the rules results in Spring application to break down.

Spring DI occurs under the above principles in which the Sping locates the most relevant unique bean and failing to find one results in the application failing.

For multiple beans candidates, by specifying their priorities or assigning names, developers could gain more control over the Spring DI.

@Primary is a good example where it indicates that a specific bean should be prioritised when multiple beans are eligible to be autowired to a single-valued dependency:

@Primary

@Configuration
public class MovieConfiguration {

	@Bean
	@Primary
	public MovieCatalog firstMovieCatalog() { ... }

	@Bean
	public MovieCatalog secondMovieCatalog() { ... }

	// ...
}

Similarly, @Qualifier assigns extra layer of Spring Bean-specific identifiers in which invoking such identifier instructs Spring IoC to inject such dependency:

@Qualifier

@Configuration
public class MovieConfiguration {

	@Bean
	@Qualifier("main")
	public MovieCatalog firstMovieCatalog() { ... }

	@Bean
    @Qualifier("notMain")
	public MovieCatalog secondMovieCatalog() { ... }

	// ...
}
public class MovieRecommender {

	@Autowired
	@Qualifier("main")
	private MovieCatalog movieCatalog;

	// ...
}

πŸ“š References

μŠ€ν”„λ§ μž…λ¬Έμ„ μœ„ν•œ μžλ°” 객체 μ§€ν–₯의 원리와 이해
Spring Doc
Geeks for Geeks
F-Lab

profile
Hello

0개의 λŒ“κΈ€