본문 바로가기
Spring

IoC / DI

by step 1 2021. 6. 12.
반응형

IoC(Inversion of Control)

스프링에서는 일반적인 Java 객체를 new로 생성하여 개발자가 관리하는 것이 아닌 Spring Container에 모두 맡긴다.

즉, 개발자에서 -> 프레임워크로 제어의 객체 관리의 권한이 넘어 갔음 으로 "제어의 역전"이라고 한다.

 

DI(Dependency Injection)

DI 장점

  • 의존성으로 부터 격리시켜 코드 테스트에 용이하다.
  • DI를 통하여, 불가능한 상황을 Mock와 같은 기술을 통하여, 안정적으로 테스트 가능하다.
  • 코드를 확장하거나 변경 할 때 영향을 최소화 한다. (추상화)
  • 순환참조를 막을 수 있다.

DI(의존성 주입) 예제

encode를 해야하는 상황에서 method를 실행해줄 interface를 생성후 상속받아 사용

 

Encode Method를 상속해줄 Interface

package com.example.ioc;

public interface IEncoder {
    String encode(String message);
}

Base64Encode

package com.example.ioc;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Base64Encoder implements IEncoder{

    public String encode(String message){
        return Base64.getEncoder().encodeToString(message.getBytes());
    }
}

URL Encode

package com.example.ioc;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class UrlEncoder implements IEncoder{

    public String encode(String message){
        try {
            return URLEncoder.encode(message, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
}

사용자가 선택한 Encode 값에 따라 인터페이스가 동작하는 코드

package com.example.ioc;

import java.util.Base64;

public class Encoder {

    private IEncoder iEncoder;

    public Encoder(IEncoder iEncoder){
        this.iEncoder = iEncoder;
    }

    public String encode(String message){

        return iEncoder.encode(message);
    }
}

Main(사용자가 원하는 Encode 선택하여 실행)

package com.example.ioc;

public class Main {

    public static void main(String[] args) {
        String url = "www.naver.com/books/it?page=10&size=20&name=spring-book";

        // Base 64 encoding
        //Base64Encoder encoder = new Base64Encoder();
        IEncoder encoder = new Base64Encoder();
        String result = encoder.encode(url);
        System.out.println(result);

        // URL encoder
        //UrlEncoder urlEncoder = new UrlEncoder();
        IEncoder urlEncoder = new UrlEncoder();
        String urlResult = urlEncoder.encode(url);
        System.out.println(urlEncoder);

        // DI 코드(외부에서 주입을 받는다)
        Encoder encoder2 = new Encoder(new Base64Encoder());
        String result2 = encoder2.encode(url);
        System.out.println("result2: " + result2);

        Encoder encoder3 = new Encoder(new UrlEncoder());
        String result3 = encoder3.encode(url);
        System.out.println("result3: " + result3);

    }
}

 

IoC 예제(스프링에서 객체 관리)

@Component: 스프링에서 관리하는 클래스로 선언(bean)
기존에 작성된 클래스에 어노테이션 추가(bean으로 등록, spring이 실행될때 객체를 싱글톤으로 만들어서 스프링 컨테이너에서 관리)

 

스프링컨테이너에 직접 접근하여 객체를 가져오기 위해 ApplicationContext 사용

class 작성

package com.example.ioc;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

// @Component: 스프링에서 관리하는 클래스로 선언(bean)
@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;
    }
}
package com.example.ioc;

import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

// @Component: 스프링에서 관리하는 클래스로 선언(bean)
// bean의 이름을 사용자가 지정할 수 있다.
@Component("base74Encoder")
public class Base64Encoder implements IEncoder{

    public String encode(String message){
        return Base64.getEncoder().encodeToString(message.getBytes());
    }
}
package com.example.ioc;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.Base64;

// @Component: 스프링에서 관리하는 클래스로 선언(bean)
//@Component
public class Encoder {

    private IEncoder iEncoder;

    public Encoder(IEncoder iEncoder){
        this.iEncoder = iEncoder;
    }

    // 기본적으로 Base64Encoder를 사용한다는 가정
    // @Qualifier: bean의 이름을 지정할 수 있다.
   /*
   public Encoder(@Qualifier("base74Encoder") IEncoder iEncoder){
        this.iEncoder = iEncoder;
    }
    */


    public void setiEncoder(IEncoder iEncoder){
        this.iEncoder = iEncoder;
    }

    public String encode(String message){

        return iEncoder.encode(message);
    }
}
package com.example.ioc;

import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

// @Component: 스프링에서 관리하는 클래스로 선언(bean)
@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;
        }
    }
}

 

@Configuration: 하나의 클래스에서 여러 Bean을 등록할 때 선언하는 어노테이션

그안에는 @Bean("name")으로 Bean을 지정한다.

package com.example.ioc;

import org.springframework.beans.factory.annotation.Configurable;
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;

import java.util.Base64;

@SpringBootApplication
public class IocApplication {

    public static void main(String[] args) {
        SpringApplication.run(IocApplication.class, args);

        ApplicationContext context = ApplicationContextProvider.getContext();

        // bean을 찾는다
/*        Base64Encoder base64Encoder = context.getBean(Base64Encoder.class);
        UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
        Encoder encoder = new Encoder(base64Encoder);
        String url = "www.naver.com/books/it?page=10&size=20&name=spring-book";

        String result = encoder.encode(url);
        System.out.println(result);

        encoder.setiEncoder(urlEncoder);
        result = encoder.encode(url);
        System.out.println(result);*/

//        기본적으로 base64encoder를 사용한다는 가정(new를 사용하지 않는다)
        Encoder encoder = context.getBean("base64Encode",Encoder.class);
        String url = "www.naver.com/books/it?page=10&size=20&name=spring-book";
        String result = encoder.encode(url);
        System.out.println(result);

        encoder = context.getBean("urlEncode", Encoder.class);
        result = encoder.encode(url);
        System.out.println(result);

    }

}

// 하나의 클래스에서 여러 bean을 생성
@Configuration
class AppConfig{

    @Bean("base64Encode")
    public Encoder encoder(Base64Encoder base64Encoder){
        return new Encoder(base64Encoder);
    }

    @Bean("urlEncode")
    public Encoder encoder(UrlEncoder urlEncoder){
        return new Encoder(urlEncoder);
    }
}

 

아래와 같은 돋보기 모양을 클릭하면 bean으로 등록된 클래스들을 확인할 수 있다.

반응형

'Spring' 카테고리의 다른 글

주요 어노테이션  (0) 2021.06.13
AOP  (0) 2021.06.13
Spring 핵심  (0) 2021.06.12
Object Mapper  (0) 2021.06.12
Response 내려주기  (0) 2021.06.12