춤추는 개발자

[Spring] 스프링의 핵심! 제어의 역전(IoC) 본문

Developer's_til/스프링 프레임워크

[Spring] 스프링의 핵심! 제어의 역전(IoC)

Heon_9u 2021. 8. 18. 17:43
728x90
반응형

 

 

 

 앞선 포스팅에서 DAO를 활용한 코드의 분리와 확장에 대해 알아보았습니다. IoC에 대한 이해를 돕기 위해 초기 DAO코드를 예로 들어보겠습니다.

 

  •  초기 UserDao를 보면 테스트용 main() 메서드는 UserDao 클래스의 오브젝트를 직접 생성 및 만들어진 오브젝트의 메서드를 사용.
  •  UserDao는 자신이 사용한 ConnectionMaker의 구현 클래스를 자신이 결정하고, 그 오브젝트를 필요한 시점에 생성하여 각 메서드에 맞게 사용.

 모든 오브젝트가 능동적으로 자신이 사용할 클래스를 결정하고, 언제 어떻게 그 오브젝트를 만들지 스스로 관장합니다. 이렇게 모든 종류의 작업을 사용하는 쪽에서 제어하는 구조입니다.

 

 제어의 역전(IoC)이란 이런 제어 흐름의 개념을 거꾸로 뒤집는 것을 의미합니다. 지난 포스팅에서 DAO개선 작업의 초기에 적용한 템플릿 메서드 패턴도 제어의 역전이라는 개념이 활용됐습니다.

 

 추상 UserDao를 상속한 서브클래스는 getConnection() 메서드를 구현합니다. 하지만, 서브클래스는 이 메서드가 어떻게, 언제 사용될지 모릅니다. 이러한 기능을 만들었을뿐 단지, 메인 클래스인 UserDao가 add(), get() 메서드를 사용할 때마다 getConnection() 메서드를 호출해서 사용하는 것입니다.

 

 즉, 제어권을 상위 템플릿 메서드로 넘기고, 자신은 필요할 때 호출되어 사용되도록 한다는, 제어의 역전이 활용된 것입니다.

 

✅ UserDaoTest 관심사 분리하기

 추가적인 설명을 위해 DAO코드를 아래와 같이 리팩토링해보겠습니다.

public class UserDaoTest {

    public static void main(String[] ars) throws ClassNotFoundException, SQLException {
        UserDao dao = new DaoFactory().userDao();
        ...
    }
}

 

public class DaoFactory {
    public UserDao userDao() {
        return new UserDao(connectionMaker());
    }

    public ConnectionMaker connectionMaker() {
        return new A_ConnectionMaker();
    }
}

 

 UserDao를 테스트하는 UserDaoTest 클래스ConnectionMaker 구현 클래스의 오브젝트를 결정하고 UserDao 오브젝트를 생성하는 DaoFactory 클래스를 생성했습니다. 앞선 포스팅에서 작성한 UserDao를 테스트하는 클래스를 관심사에 따라 한번 더 분리한 결과입니다.

 

 해당 코드에도 제어의 역전이 적용되어 있습니다. UserDao는 자신이 어떤 ConnectionMaker 구현 클래스를 만들고 사용할지 결정할 권한을 DaoFactory에게 넘겼으니, 수동적인 존재가 되었습니다. 게다가, UserDaoTest도 DaoFactory가 제공하는 ConnectionMaker를 사용할 수 밖에 없습니다.

 

 관심사를 분리하고 책임을 나누면서 유연하고 확장 가능한 구조로 만들었던 과정이 자연스럽게 IoC를 적용한 작업이었던 것입니다.

 

✅ 스프링의 IoC

 위에 작성한 DAO에 스프링의 IoC를 적용해보겠습니다. 스프링의 IoC를 알기 전에 스프링의 핵심인 빈 팩토리 또는 어플리케이션 컨텍스트라고 불리는 용어를 짚고 넘어가겠습니다.

 

 스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 이라고 부릅니다. 동시에 스프링 빈은 스프링 컨테이너가 생성과 관계 설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리키는 말입니다.

 

 이러한 빈의 생성과 관계 설정같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리라고 부릅니다. 이와 비슷한 어플리케이션 컨텍스트는 IoC 방식을 따라 만들어진 일종의 빈 팩토리라고 생각하면 됩니다.

 굳이 둘을 비교하자면, 빈 팩토리는 IoC의 기본 기능에 초점을 맞춘 것, 어플리케이션 컨텍스트는 어플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 강조되어 있습니다.

DaoFactory를 사용하는 어플리케이션 컨텍스트

 위에 작성한 DaoFactory 자체가 설정 정보까지 담고 있는 IoC 엔진입니다. 이를 어플리케이션 컨텍스트의 설정 정보로 활용해보겠습니다.

 

 먼저, 스프링이 빈 팩토리를 위한 오브젝트 설정을 담당하는 클래스라고 인식할 수 있도록 @Configuration을 추가합니다. 그리고 오브젝트를 만드는 메서드에는 @Bean을 추가합니다. 이 2가지 어노테이션은 어플리케이션 컨텍스트가 IoC 방식의 기능을 제공할 때 사용할 설정 정보가 된 것입니다.

@Configuration
public class DaoFactory {

    @Bean
    public UserDao userDao() {
        return new UserDao(connectionMaker());
    }

    @Bean
    public ConnectionMaker connectionMaker() {
        return new A_ConnectionMaker();
    }
}

 

 이제 UserDaoTest 클래스에서 DaoFactory를 설정 정보로 사용하는 어플리케이션 컨텍스트를 만들어보겠습니다. 그리고 ApplicationContext에 등록된 빈의 이름에 따라 getBean() 메서드를 활용합니다.

public class UserDaoTest {

    public static void main(String[] ars) throws ClassNotFoundException, SQLException {
        ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
        UserDao dao = context.getBean("userDao", UserDao.class);
        ...
    }
}

 

 위처럼 ApplicationContext가 동작하는 방식은 아래와 같습니다. @Configuration이 붙은 DaoFactory는 어플리케이션 컨텍스트가 활용하는 IoC 설정 정보입니다. 그리고 내부적으로 @Bean이 붙은 메서드의 이름을 가져와 빈 목록을 만들어줍니다. 

출처: https://frontierdev.tistory.com/76

 

 굳이, Annotation을 추가하고 ApplicationContext까지 만들면서 IoC를 사용하는 이유는 크게 3가지입니다.

 

  1. 오브젝트는 구체적인 팩토리 클래스를 알 필요가 없다.
  2. 어플리케이션 컨텍스트는 종합 IoC 서비스를 제공한다.
  3. 어플리케이션 컨텍스트는 빈은 검색하는 다양한 방법을 제공한다.

✅ 스프링 IoC의 용어 정리

 지금까지 IoC에 관련된 용어들에 대해 한번 정리하고 넘어가보겠습니다.

[ 빈(Bean) ]

 빈 또는 빈 오브젝트는 스프링이 IoC 방식으로 관리하는 오브젝트라는 뜻입니다. 어플리케이션에서 만들어지는 오브젝트 중 스프링이 직접 생성과 제어를 담당하는 오브젝트만을 빈이라고 부릅니다.

 

[ 빈 팩토리(Bean Factory) ]

 스프링의 IoC를 담당하는 핵심 컨테이너입니다. 빈을 등록하고, 생성, 조회, 리턴 등 관리하는 기능을 담당합니다. 보통 이를 확장한 어플리케이션 컨텍스트를 이용합니다.

 

[ 어플리케이션 컨텍스트(ApplicationContext) ]

 빈 팩토리를 확장한 IoC 컨테이너입니다. 스프링이 제공하는 각종 부가 서비스를 추가로 제공하며 ApplicationContext는 BeanFactory를 상속합니다. 스프링에 제공하는 어플리케이션 지원 기능을 모두 포함한 것을 뜻합니다.

 

[ 설정정보/설정 메타정보 ]

 스프링의 설정정보란 어플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타 정보를 의미합니다. 스프링의 설정정보는 컨테이너에 어떤 기능을 세팅하거나 조정하는 경우에도 사용되지만, IoC 컨테이너에 의해 관리되는 어플리케이션 오브젝트를 생성하고 구성할 때 사용됩니다.

 

[ 컨테이너 또는 IoC 컨테이너 ]

 IoC 방식으로 빈을 관리한다는 의미에서 어플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고도 합니다. 컨테이너라는 말 자체가 IoC의 개념을 담고 있다는 점만 알고 있으면 됩니다. 때로 '스프링에 빈을 등록하고'라는 식으로 스프링이라는 단어가 컨테이너라는 의미를 담고 있기도 합니다.

 

🙋‍♂️ 느낀점

 제어의 역전이라는 의미를 '개발자가 제어할 작업들을 스프링이 대신 해준다.' 라는 정도로만 이해하고 있었다. 하지만, 직접 Annotation을 적용하며 컨테이너에 빈을 등록하고, 생성하는 과정들을 통해 IoC의 이점과 관련 용어들을 정확하게 이해할 수 있었다.

 

 코드의 분리와 확장을 하는 과정에서 자연스럽게 IoC가 적용된다는 점이 인상깊었다. 앞으로 스프링에 대해 갈 길이 멀지만, 하나하나 알아가는 재미가 쏠쏠하다. 특히, 공부할 때마다 더 나은 개발자로 성장하는 기분이 든다.👏

 

 

728x90
반응형