개발공부/Spring
[Spring] IoC (Inversion of Control), DI
환타몬
2022. 2. 10. 17:42
IoC
- IoC (Inversion of Control) - 스프링에서는 일반적 Java 객체를 new로 생성하여 개발자가 관리하는 것이 아닌 Spring Container에 모두 맡긴다. 즉 개발자에서 프레임워크로 제어의 객체 관리의 권한이 넘어 갔으므로 "제어의 역전" 이라 함.
DI
장점
- 의존성으로부터 격리시켜 코드테스트이 용이하다.
- DI를 통하여 불가능한 상황을 Mock과 같은 기술을 통하여 안정적으로 테스트 가능하다.
- 코드를 확장하거나 변경할 때 영향을 최소화한다 (추상화)
- 순환참조를 막을 수 있다.
아래의 코드들은 DI, IoC의 과정을 간략하게 테스트해보는 것이다.
- ApplicationContextProvider.java
package com.example.springioc;
import org.apache.catalina.core.AprLifecycleListener;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component //Spring에서 Component로 관리
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext(){
return context;
}
}
- Base64Encoder.java
package com.example.springioc;
import org.springframework.stereotype.Component;
import java.util.Base64;
@Component("base74Encoder") //@Qualifier에서 사용될 Component명
public class Base64Encoder implements IEncoder{
public String encode(String message){
return Base64.getEncoder().encodeToString(message.getBytes());
}
}
- Encoder.java
package com.example.springioc;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
public class Encoder {
private IEncoder iEncoder;
//Component가 두개 이상일 때 spring이 결정하지 못함. 그럴 때 @Qualifier("base74Encoder") 어노테이션으로 명시해줌.
public Encoder(IEncoder iEncoder){
this.iEncoder = iEncoder;
}
public void setIEncoder(IEncoder iEncoder){
this.iEncoder = iEncoder;
}
public String encode(String message){
return iEncoder.encode(message);
}
}
- IEncoder.java
package com.example.springioc;
public interface IEncoder {
String encode(String message);
}
- SpringiocApplication.java
package com.example.springioc;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication //bean = 스프링 컨테이너에서 관리되는 객체
public class SpringiocApplication {
public static void main(String[] args) {
SpringApplication.run(SpringiocApplication.class, args);
ApplicationContext context = ApplicationContextProvider.getContext();
//Base64Encoder base64Encoder = context.getBean(Base64Encoder.class);
//UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
Encoder encoder = context.getBean("urlEncode", Encoder.class);
String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";
String result = encoder.encode(url);
System.out.println(result);
}
}
@Configuration // 한 개의 클래스에서 여러 개의 bean을 등록
class AppConfig{
@Bean("base64Encode")
public Encoder encoder(Base64Encoder base64Encoder){
return new Encoder(base64Encoder);
}
@Bean("urlEncode")
public Encoder encoder(UrlEncoder url64Encoder){
return new Encoder(url64Encoder);
}
}
- UrlEncoder.java
package com.example.springioc;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Component
public class UrlEncoder implements IEncoder{
public String encode(String message){
try {
return URLEncoder.encode(message, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
정리
- 스프링에서 객체를 bean이라 함.
- 스프링에서 객체를 직접 관리되는 장소가 Container
- 개발자들의 권한을 스프링 컨테이너가 가져갔기 때문에 제어의 역전이라 함. (IoC)
- @Component annotation - 스프링에서 component를 통해 bean으로 받고 이를 직접 관리함.
- @Component("base64Encoder") 와 같이 Component를 통해 명명 가능
- 만약 Component가 두 개 이상이라면 스프링에서 가져와야 할 클래스를 결정 내리지 못하기 때문에 @Qualifier annotation을 통해서 가져올 Component의 이름을 받는다.
- @Configuration annotation - 하나의 클래스에서 여러 개의 bean을 등록