개발새발/Spring

220219_스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(2)_패스트캠퍼스 챌린지 27일차

막동이아빠 2022. 2. 19. 23:49

220219_스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(2)_패스트캠퍼스 챌린지 27일차

<2022년 02월 19일 _ 패스트캠퍼스 챌린지 27일차>

[스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(2)]

지난강의에 이어집니다~

https://mylife4hi.red/56

 

220218_스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(1)_패스트캠퍼스 챌린지 26일차

220218_스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(1)_패스트캠퍼스 챌린지 26일차 [스프링 입문_스프링을 조금 더 들여다보기_IoC, DI(1)] 1. IoC (Inversion Of Control)  : 스프링에서는 일반적인 Java..

mylife4hi.red

1. IoC (Inversion Of Control)

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

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

 

2. DI (Dependency Injection)

 : 의존성으로부터 격리시켜 코드 테스트에 용이함

 : DI를 통해, 불가능한 상황을 Mock와 같은 기술을 통해, 안정적으로 테스트 가능

 : 코드를 확장하거나 변경 할 때 영향을 최소화 함(추상화)

 : 순환 참조를 막을 수 있다.

 

3. 실습_IoC

 (1) File > New > Project > Spring Initializr

   : Artifact(spring-ioc), Language(Java), Type(Gradle), Java(11), Packaging(Jar) Next 클릭

   : Web(Spring Web) 체크 Finish 클릭

 (2) 이전 프로젝트에서 Main을 제외하고 복사해 옵시다

package com.example.springioc;

public interface IEncoder {
    String encode(String message);
}
package com.example.springioc;

public class Encoder implements IEncoder{

    private IEncoder iEncoder;

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

    public String encode(String message){
        return iEncoder.encode(message);
    }
}
package com.example.springioc;

import java.util.Base64;

public class Base64Encoder implements IEncoder{

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

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;
        }
    }
}

: DI를 설명하며 작성한 클래스들, 개발자가 직접 만든 객체를 주입해주었다.

: IoC는 Spring container가 이런 것들을 직접 생성해주므로, 생명주기까지 모두 가져가준다

 

(3) Base64Encoder, UrlEncoder 를 객체로 관리해달라는 요청을 해봅시다~

@Component

클래스 명 위에 @Component 어노테이션을 붙여줍니다

 그럼 다음과 같이 Spring 이 실행이 될때 @Component 어노테이션이 붙은 객체를 singleton 형태로 만들어 Bean으로 관리를 하게 된다

그럼 이 것들을 어떻게 꺼내서 쓸까요?

 (4) ApplicationContextProvider 클래스를 추가하고, ApplicationContextAware를 상속해줍니다

package com.example.springioc;

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

@Component
public class ApplicationContextProvider implements ApplicationContextAware {

    private static ApplicationContext context;

    //외부로부터 ApplicationContext를 주입 받는데, Spring이 자동으로 주입해준다!
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getContext(){
        return context;
    }
}

 : Spring 어플리케이션이 실행이 되어 ApplicationContextProvider 를 만들 때, set 메소드에 ApplicationContext를 주입 해주고, context에 해당 applicationContext를 할당하면, 우리는 getContext()로 가져다 쓰면 된다.

 

 (5) 그럼 Main문을 작성 해보자

package com.example.springioc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringIocApplication {

    public static void main(String[] args) {
        //Spring 어플리케이션의 실행
        SpringApplication.run(SpringIocApplication.class, args);

        ApplicationContext context = ApplicationContextProvider.getContext();


        //주입을 IoC로 하므로 객체 관리를 new 로 하지 않는다
        Base64Encoder base64Encoder = context.getBean(Base64Encoder.class);
        Encoder encoder = new Encoder(base64Encoder);
        String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";

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

}

실행결과:

d3d3Lm5hdmVyLmNvbS9ib29rcy9pdD9wYWdlPTEwJnNpemU9MjAmbmFtZT1zcHJpbmctYm9vdA==

 

 (6) Main 문을 추가 작성해줍시다

UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
result = urlEncoder.encode(url);
System.out.println(result);

전체 Main 코드

package com.example.springioc;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringIocApplication {

    public static void main(String[] args) {
        //Spring 어플리케이션의 실행
        SpringApplication.run(SpringIocApplication.class, args);

        ApplicationContext context = ApplicationContextProvider.getContext();

        String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";

        //주입을 IoC로 하므로 객체 관리를 new 로 하지 않는다
        Base64Encoder base64Encoder = context.getBean(Base64Encoder.class);
        Encoder encoder = new Encoder(base64Encoder);
        String result = encoder.encode(url);
        System.out.println(result);

        UrlEncoder urlEncoder = context.getBean(UrlEncoder.class);
        result = urlEncoder.encode(url);
        System.out.println(result);
    }

}

 

결과:

d3d3Lm5hdmVyLmNvbS9ib29rcy9pdD9wYWdlPTEwJnNpemU9MjAmbmFtZT1zcHJpbmctYm9vdA==
www.naver.com%2Fbooks%2Fit%3Fpage%3D10%26size%3D20%26name%3Dspring-boot

 

둘다 모두 스프링에서 관리되도록 제어의 역전이 일어났다!! IoC!

 

그렇다면 Encoder도 스프링에서 관리해주도록 해보면 어떨까?

 

 (7) Encoder에 @Component 를 붙여준다!

@Component
public class Encoder implements IEncoder{

   : 생성자의 파라미터에서 IEncoder가 UrlEncoder인지 Base64Encoder인지 인식하지 못해 오류가 발생한다.

public Encoder(@Qualifier("urlEncoder") IEncoder iEncoder){
    this.iEncoder = iEncoder;
}
public Encoder(@Qualifier("base64Encoder") IEncoder iEncoder){
    this.iEncoder = iEncoder;
}

   : 생성자의 파라미터 앞에 @Qualifier 에 Bean의 이름을 넣어주어 지정하면, 오류가 발생하지 않는다~

 

  (8) Main문 추가 작성

//기본 할당한 것으로 할당이 된다~!!
Encoder defaultEncoder = context.getBean(Encoder.class);;
result = defaultEncoder.encode(url);
System.out.println(result);

결과:

d3d3Lm5hdmVyLmNvbS9ib29rcy9pdD9wYWdlPTEwJnNpemU9MjAmbmFtZT1zcHJpbmctYm9vdA==

 

  --> 이제 코드에서 new로 생성하는 부분을 찾을 수 없다.

  --> 스프링에서 모든 생명주기가 관리가 가능하다

 

두개의 Encoder를 생성자에서 사용하고 싶은데 어떻게 할까?

 

 (9) Encoder 소스 변경

   : Component 어노테이션, Qualifier 어노테이션 제거

    --> Appconfig 클래스 추가

package com.example.springioc;

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
public class SpringIocApplication {

    public static void main(String[] args) {
        //Spring 어플리케이션의 실행
        SpringApplication.run(SpringIocApplication.class, args);

        ApplicationContext context = ApplicationContextProvider.getContext();

        String url = "www.naver.com/books/it?page=10&size=20&name=spring-boot";

        //기본 할당한 것으로 할당이 된다~!!
        Encoder encoder = context.getBean("base64Encode" ,Encoder.class);;
        String result = encoder.encode(url);
        System.out.println(result);

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

}

@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);
    }
}

결과:

d3d3Lm5hdmVyLmNvbS9ib29rcy9pdD9wYWdlPTEwJnNpemU9MjAmbmFtZT1zcHJpbmctYm9vdA==
www.naver.com%2Fbooks%2Fit%3Fpage%3D10%26size%3D20%26name%3Dspring-boot

 

 

정리:

 - 주입 받기 위해서는, 생성자 or set메소드 or auto wired나 injector등의 어노테이션을 이용한다

 - 스프링에서 객체를 직접 관리하는 것 : Bean

 - Bean들이 관리되고 있는 장소 : Spring container

 - 스프링에서 이러한 객체의 제어 권한을 가져갔다 : 제어의 역전! = IoC

 

 

27일차 강의 완료~

필기 & 내 화면 스크린샷 저장

 

https://bit.ly/37BpXiC

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.