IoC 컨테이너? 빈? ApplicationContext?

maketheworldwise·2022년 4월 6일
0


이 글의 목적?

스프링의 삼각형 이해하기! 포스트에서 의존성 주입에 대한 방법에 대해서는 숙지를 했지만, 각 개념에 대한 질문이 들어왔을 때 - 사용 방법이 아닌 조금 더 제대로된 답변을 할 수 있도록 개념을 정리해보자.

IoC 컨테이너?

IoC(Inversion of Control)는 어떤 객체가 사용하는 의존 객체를 직접 만들어 사용하는 것이 아닌 주입을 받아 사용하는 방법이라고 했다. 그렇다면 IoC 컨테이너는 뭘까?

(정답을 말하자면, IoC 컨테이너는 빈을 관리해주는 친구다. 😃)

스프링 IoC 컨테이너의 가장 최상위에 있는 인터페이스는 BeanFactory가 있다. BeanFactory는 IoC 컨테이너의 가장 핵심적인 클래스이며, 다양한 라이프사이클 인터페이스들이 존재하는 것을 확인할 수 있다. 이러한 라이프사이클 인터페이스를 이용하면, 컨테이너 내부의 빈들을 조작하는 등 다양한 작업을 처리할 수 있다.

Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:

1. BeanNameAware's setBeanName
2. BeanClassLoaderAware's setBeanClassLoader
3. BeanFactoryAware's setBeanFactory
4. EnvironmentAware's setEnvironment
5. EmbeddedValueResolverAware's setEmbeddedValueResolver
6. ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
7. ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
8. MessageSourceAware's setMessageSource (only applicable when running in an application context)
9. ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
10. ServletContextAware's setServletContext (only applicable when running in a web application context)
11. postProcessBeforeInitialization methods of BeanPostProcessors
12. InitializingBean's afterPropertiesSet
13. a custom init-method definition
14. postProcessAfterInitialization methods of BeanPostProcessors

On shutdown of a bean factory, the following lifecycle methods apply:

1. postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
2. DisposableBean's destroy
3. a custom destroy-method definition

빈?

빈은 스프링 IoC 컨테이너가 관리하는 객체를 의미한다. 빈이 가지고 있는 이점으로는, 가장 대표적으로 의존성 관리가 있다. (의존성 주입을 받고 싶을 경우에는 반드시 빈으로 등록이 되어있어야 함!)

또 다른 이점으로는 싱글톤 스코프에서의 장점이다. IoC 컨테이너에 등록되는 빈들은 기본적으로 싱글톤 스코프로 등록된다. 따라서 애플리케이션에서 싱글톤 빈을 받아와 사용한다면, 메모리와 런타임 성능 최적화에도 유리해진다.

마지막으로 위에서도 말했지만, 라이프사이클 인터페이스를 지원해준다. 다양한 라이프사이클 인터페이스를 이용하면 빈이 생성되었을 때 추가적인 작업을 할 수 있다.

💡 스프링 빈? 자바 객체? 빈 객체?

빈은 스프링 IoC 컨테이너에서 사용되는 개념으로, 컨테이너에 의해 인스턴스화되어 조립되거나 관리되는 객체를 의미한다. 즉, 용어만 다를 뿐 모두 동일한 개념이다.

ApplicationContext?

ApplicationContext는 쉽게 말하자면 BeanFactory에 비해 더 다양한 기능을 가지고 있는 인터페이스다. 그 이유는 ApplicationContext 공식 문서와 많은 상위 인터페이스를 implements 하는 소스 코드만 보아도 알 수 있다.

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    @Nullable
    String getId();

    String getApplicationName();

    String getDisplayName();

    long getStartupDate();

    @Nullable
    ApplicationContext getParent();

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

즉, ApplicationContext 하나만으로도 많은 것을 수행할 수 있다.

  • BeanFactory
  • 메시지 소스 처리 기능 (i18n)
  • 이벤트 발행 기능
  • 리소스 로딩 기능
  • ...

ApplicationContext를 이용하여 빈의 정보를 가져오길 원한다면 하단의 코드처럼 구성해주면 된다.

public class Application {

    public static void main(String[] args) {
        // ApplicationContext context = new ClassPathXmlApplicationContext("application-scanning.xml");
        ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);

        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames)); // 등록되어 있는 모든 빈 확인

        BookService bookService = (BookService) context.getBean("bookService");
        System.out.println(bookService.bookRepository != null); // bookRepository 의존성 주입 확인
    }

}

💡 Spring Boot에서는 ApplicationContext 객체가 어디에서 생성이 될까?

Spring Boot를 이용하다보면, 직접 ApplicationContext을 구성하거나 거의 사용을 하지 않는다. 그럼 ApplicaitonContext 객체는 어디에 있고 어떻게 생성이 되고 있을까?

답은 SpringApplication 클래스의 run() 메서드에서 생성이 된다. 하단의 코드처럼, 기본적으로 Spring Boot 프로젝트를 만들면 나오는 메인 메서드에서 run() 메서드를 실행시키는 것을 볼 수 있다.

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

그리고 코드를 따라가보면, ApplicationContext가 생성이 되는 코드를 확인할 수 있다.

public ConfigurableApplicationContext run(String... args) {
        // (생략...)
        ConfigurableApplicationContext context = null;
        // (생략...)
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);
        // (생략...)

결국엔 이를 통해서 알 수 있는 것은 - 프로젝트를 생성했을 때 자동으로 생성되는 메인 클래스 자체가 바로 빈 설정 파일이라고 볼 수 있다는 것이다.

이 글의 레퍼런스

  • 백기선님의 스프링 프레임워크 핵심 기술
profile
세상을 현명하게 이끌어갈 나의 성장 일기 📓

0개의 댓글