IoC(Inversion Of Control)란?

IoC는 제어의 역전을 뜻합니다.
제어의 역전.. 제어가 역전된다.. 이게 어떤 의미일까요?

 

기존의 프로그램은 구현 객체가 프로그램의 제어 흐름을 조종합니다.
즉 사용자에 의해서 흐름이 제어되며 프로그램은 사용자가 만들어놓은 흐름에 따라 실행 될 뿐입니다.

 

IoC는 이 상태를 반전시킨 것으로 사용자에 의해 흐름이 제어되는 것이 아닌 프로그램 자체가 제어권을 갖는 것입니다.

 

Non - IoC Exapmle

public class Main {


    public static void main(String[] args) {


        MemoryMemberRepository memoryMemberRepository = new MemoryMemberRepository();
        MemberService memberService = new MemberServiceImpl(memoryMemberRepository);

        /**
         * memberService 를 이용한 코드
         */

    }

}

 

일반적인 형태의 코드입니다.

 

main문 안에서 필요한 객체들을 생성하고 사용하게 됩니다

이 경우 해당 객체들의 생명주기는 main이 시작하면서 생성되고 main이 종료되면서 삭제됩니다.

 

만약 사용자가 코드를 변경한다면

public class Main {

    public static MemberService memberService = new MemberServiceImpl(new MemoryMemberRepository());

    public static void main(String[] args) {

        /**
         * memberService 를 이용한 코드
         */

    }

}

 

객체들의 생명주기는 클래스가 로드될때 생성되고 프로그램 종료시 삭제됩니다.

또한 사용자가 언제 memberService를 호출해 사용할 지 흐름을 정의할 수 있습니다.

 

사용자가 코드를 만드는 방식에 따라서 객체의 생명주기와 동작의 흐름이 바뀌게되며

이는 사용자가 프로그램의 제어 흐름을 조종하는 것과 같습니다.

 

IoC는 이러한 흐름을 역전시켜 프로그램이 자체적으로 흐름을 제어하는 것입니다.

 

IoC Exapmle

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memoryMemberRepository());
    }

    @Bean
    public MemoryMemberRepository memoryMemberRepository() {
        return new MemoryMemberRepository();
    }

}

 

Spring FrameWork에서 자바 코드를 이용해 Bean을 등록하는 코드입니다.

 

이 코드를 통해서 MemberService , MemoryMemberRepository는 Spring Bean의 형태로 Context에 등록됩니다.

또한 Bean들의 생명주기또한 Context가 스스로 제어합니다.

 

사용자는 이 과정에 개입하지 않으며 모든 동작은 Spring이 정의해놓은 순서와 규칙을 통해 이루어집니다.

 

즉 사용자에게 제어권이있는게 아닌 프로그램 자체가 제어권을 갖고있는 것입니다.
이것을 제어권이 역전되었다 , IoC 되었다 라고 말합니다.

 

FrameWork없이 순수 자바코드로도 가능합니다.

@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    enum Method{
        POST,GET
    }
    String[] value();
    Method method() default Method.GET;

}

(사용자정의 어노테이션)

public void initialize(Set<Class<?>> c, ServletContext ctx) {

        if (Objects.isNull(c)) {
            log.info("Controller not found");
            return;
        }

        for (Class<?> controllerClass : c) {
            try {
                Constructor<?> constructor = controllerClass.getConstructor();
                Object controllerInstance = constructor.newInstance();

                RequestMapping requestMapping = controllerClass.getAnnotation(RequestMapping.class);
                if (requestMapping != null) {
                    String[] values = requestMapping.value();

                    for (String value : values) {
                        String key = getKey(requestMapping.method().name(), value);
                        beanMap.put(key, controllerInstance);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }


        ctx.setAttribute(CONTEXT_CONTROLLER_FACTORY_NAME, this);

    }

 

이 코드는 Java Servlet을 이용해 WebApplication 을 구축하는 코드의 일부입니다.

(Java Servlet은 FrameWork이 아닌 순수자바)

 

Reflection 을 통해 RequestMapping 어노테이션을 갖고있는 클래스의 정보를 읽어와 객체를 생성한 후

Map에 넣어 관리하는 코드로 프로그램이 실행될 때 동적으로 클래스들을 읽어 관리하게 됩니다.

 

 

단위 테스트를 수행하는데 사용되는 프레임워크인 JUnit또한 실행 및 관리를 위한 생명주기를 갖습니다.

@SpringBootTest
class CoreApplicationTests {

    @BeforeEach
    void beforEach() {
    }

    @Test
    void contextLoads() {
    }

    @AfterEach
    void afterEach() {
    }

}

 

사용자는 @BeforeEach , @Test , @AfterEach 어노테이션만 사용하면 프로그램이 알아서 테스트로 인식하고

실행시 JUnit이 이미 정의한 동작 순서와 생명주기에 따라 테스트하게 됩니다.

 

따라서 IoC가 됐다 = 프로그램이 자체적으로 흐름을 제어한다.

이렇게 정리할 수 있습니다.

 

프로그램의 자체적인 흐름이란??

  1. 프로그램이 컨테이너를 통해 생명주기를 관리한다.
  2. 동작의 순서가 프로그램이 정의한 흐름을 따른다.

(이런 흐름에 사용자가 억지로 개입할수는 있지만 일반적인 경우만 다루겠습니다.)

 

IoC의 이점

 

IoC/DI를 구현함으로 사용영역과 구성영역을 나눌 수 있습니다.

쉽게말하면 사용자는 객체의 실행에만 신경쓰고 , 객체들의 관리와 동작의 흐름은 프로그램이 하게 하는것입니다.

// 실행영역 
public static void main(String[] args) {

        // 사용자가 객체 사용시 new 를 이용해 찍어내지 않음 , Context에 등록된 Bean을 꺼내 사용
        // 즉 객체를 사용자가 관리하는게 아님 
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);

        // 따라서 객체자체의 실행에만 집중할 수 있음 
        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member);
    }


// 여기는 구성영역 , 해당 객체들이 Bean에 등록되는 과정과 관리방법은 이미 Spring에 정의돼있음
@Configuration 
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memoryMemberRepository());
    }

    @Bean
    public MemoryMemberRepository memoryMemberRepository() {
        return new MemoryMemberRepository();
    }

}

실행하는 코드와 구성하는 코드를 분리하게 됨으로써 유지보수의 용이성과 가독성을 높여줍니다.

 

이런 IoC개념이 기본적으로 깔려있는 FrameWork는 사용자가 제어 해야 할 상당 부분들을 대신함으로써

개발 생산성을 크게 증가시켜줍니다.

 

Ex) 스프링 사용시 사용자는 객체의 

의존관계를 어떻게 주입할것 인지만 설정해주면 
Bean을 등록하고 관리하는 모든 과정은 스프링이 제어 함 (IoC/DI의 개념)

 

추가적으로 흔히 말하는 FrameWork Vs Library 의 가장 큰 차이도 IoC개념이 있냐 없냐의 차이가 가장 핵심적입니다.

 

아래는 추가로 읽으면 좋은 글입니다.

https://masiljangajji-coding.tistory.com/52

 

Dependency(의존관계)란?

Dependency(의존관계)란? 의존관계는 코드에서 두 모듈간의 연결을 의존관계라 합니다. 객체지향언어에서 두 클래스 간의 관계를 말하기도 합니다. 의존관계의 종류는 크게 4가지가 존재합니다. Dep

masiljangajji-coding.tistory.com

https://masiljangajji-coding.tistory.com/53

 

Dependency Injection(의존관계 주입)이란

Dependency Injection(의존관계 주입)이란? 이 글은 IoC , Dependency 의 개념을 알고있다는 전제하에 작성된 글입니다. 원활한 이해를 위해서 아래글을 읽어주세요 https://masiljangajji-coding.tistory.com/51 IoC(Inver

masiljangajji-coding.tistory.com

도움이 되셨으면 좋겠습니다.

'Spring > Spring Core' 카테고리의 다른 글

Dependency Injection(의존관계 주입)이란  (2) 2024.01.04
Dependency(의존관계)란?  (2) 2024.01.04

+ Recent posts