오늘은 월요일이니 간단히.
필자의 지인 중 N사에 면접에 나온 질문 중 하나다. 나도 솔직히 가물가물해서 다시 알아보기로 했다. 예전에 살짝 글로만 읽어서 그런지 까먹어서 다시 글로 남긴다.
ApplicationContext
인터페이스는 Spring을 사용한다면 누구나 잘 알려져 있는 그런 인터페이스이다. Spring에서도 아주 핵심적인 인터페이스라고도 불릴 수 있다.(필자생각)
ApplicationContext
를 역할을 간단히 설명하자면 오브젝트 생성, 관계설정, 만들어지는 방식, 자동생성, 후처리등 여러가지 일들을 한다. 아주 많은 일을 하니 이것은 따로 살펴보도록하자. 또 한
BeanFactory
를 상속받고 있다.
그럼
ApplicationContext
와
BeanFactory
차이점은 뭘까? 실제 차이점을 검색해보면 대부분 이런글들이 많다. ApplicationContext는 Pre-loading을 하고 즉, 즉시 인스턴스를 만들고
BeanFactory
는 lazy-loading을 하여 실제 요청 받는 시점에서 인스턴스를 만든다고 한다. 정리하자면 두 인터페이스의 차이점은 인스턴스화 시점이 다르다는 것이다.
헌데 조금 이상하다. 어차피
ApplicationContext
는
BeanFactory
를 상속받고 있지 않는가? BeanFactory를 사용하고 ApplicationContext의 구현체를 사용하면
Pre-loading
이 아닌거 아닌가? 즉 이런코드를 말한다.
BeanFactory beanFactory = new AnnotationConfigApplicationContext(Config.class);
final Context bean = beanFactory.getBean(Context.class);
위와 같이 사용하면 즉시 인스턴스를 만든다. 구현체는
ApplicationContext
이지만 실제 사용하는
getBean
메서드는
BeanFactory
인터페이스의 메서드이다.
그럼 다시 코드를 보자.
BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));
System.out.println("before getBean");
final Context bean = xmlBeanFactory.getBean(Context.class);
public class Context implements InitializingBean {
public String hello(){
return "hello";
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("init");
}
}
위의 코드는 XmlBeanFactory 사용해서 BeanFactory를 생성해보자. 그리고 application.xml에는 다음과 같이 빈으로 등록하자.
<bean class="me.wonwoo.Context"/>
위와 같이 빈으로 등록하면 어떤일이 발생할까? 실행시켜보자. 그럼 다음과 같은 로그가 발생한다.
before getBean
//중간생략
init
22:41:46.804 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanFactory - Finished creating instance of bean me.wonwoo.Context#0
XmlBeanFactory는 인스턴스를 먼저 만들지 않고 호출시에 인스턴스를 만드는 것을 알 수 있다. 먼저 만들어졌다면
init
이 먼저 출력 됐을 것이다. 이제 다음과 같이 변경해보자.
BeanFactory classPathXmlApplicationContext =
new ClassPathXmlApplicationContext(new String[]{"application.xml"});
System.out.println("before getBean");
final Context bean = classPathXmlApplicationContext.getBean(Context.class);
XmlBeanFactory를 ClassPathXmlApplicationContext 변경하여 다시 코드를 실행하면 다음과 같은 로그가 출력된다.
init
//중간 생략
before getBean
22:44:24.978 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean me.wonwoo.Context#0
이번에는 init이 먼저 출력되었다. 인스턴스를 먼저 생성한 것이다. 어차피 똑같은
BeanFactory
를 사용하고 구현체만 변경하였는데 다르게 동작한다.
또 어떻게 보면 맞는말 같기도 하다.
BeanFactory
가 붙은 클래스들은 lazy이고
ApplicationContext
구현체들은 모두 pre loading이니 틀린말은 아닌 것 같다. 그렇다고 아주 맞는말도 아닌거 같다.
실제 Spring 문서를 찾아봤는데 위와 같은 언급은 딱히 없는 거 같고 이런내용만 있다.
대충 간단히 정리하자면 다음과 같다.
딱히 특별한 이유가 없다면 BeanFactory 보다는 ApplicationContext를 써라. 여기서 특별한이란 메모리 소비가 중요하거나 리소스가 제한된 장치들을 말한다. 일반적인 엔터프라이즈 어플리케이션은 ApplicationContext를 사용하는 게 낫다. 그 이유는
BeanPostProcessor
확장 포인트를 사용 할 수도 있고, 트랜잭션과 AOP와 같은 상당한 양의 지원을 받을 수 있다고 하는데 맞는건지는 문서를 보면 되겠다.
Feature |
BeanFactory |
ApplicationContext |
Bean instantiation/wiring |
Yes |
Yes |
Automatic BeanPostProcessor registration |
No |
Yes |
Automatic BeanFactoryPostProcessor registration |
No |
Yes |
Convenient MessageSource access (for i18n) |
No |
Yes |
ApplicationEvent publication |
No |
Yes |
위와 같은 차이점이 있다고 한다.
ApplicationContext
인터페이스가 좀 더 확장된 인터페이스라고 생각하면 될 듯 싶다. 그치만 아직까지 lazy loading과 pre loading은 의문이다. 아닌거 같으면서도 맞는거 같고.. 구현체에 따라 달라지는거는 맞는데.. 그렇다고 딱
BeanFactory
가 lazy loading이다 라고 하기엔 아닌거 같고.. 이건 좀 더 생각을 해보자.