개발공부/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을 등록