News from 3월 17, 2010

  2010/03/17
Spring Framework에서 ApplicationContext간의 parent,child 관계 만들기
Last changed: 3월 17, 2010 09:09 by 자바지기
Labels: applicationcontext, parent, child

이번에 Spring Batch에 대한 지원 업무를 하면서 다음과 같은 요구사항이 생겼습니다. 기존에 이미 Quartz를 통하여 구현되어 있는 Batch Job이 이미 존재하는 상태이고, 각 Quartz Job이 실행될 때마다 ApplicationContext을 새로 생성해서 실행하는 구조로 되어 있었습니다. 이렇게 동작하다보니 각 Batch Job 간의 독립성을 보장하기 위한 목적으로는 좋지만 매번 같은 인스턴스를 만들어야 하는 비용적인 부담이 발생하게 됩니다.

왜 이와 같이 관리하느냐고 의아해 하는 분들도 있겠지만 그 때의 요구에 따라서 충분히 만들어질 수 있는 구조라 생각합니다. 이와 같이 독립적으로 실행하고 독립적으로 관리할 경우 Batch Job 간의 의존 관계를 만들려고 해도 만들기 쉽지 않은 구조가 되기 때문에 개발자가 많거나 개발자의 변경이 많은 경우에는 나름 좋은 선택이라고 생각합니다. 물론 개인적으로 이 선택에 찬성하지는 않지만요.

그런데 이 같은 구조를 한번에 모두 바꾸기에는 운영하는 측에서 부담스러워하더군요. 그래서 단계적으로 변경해 가기로 했습니다. 먼저 각 Batch Job에서 공통적으로 사용하는 부분을 서블릿 컨테이너가 시작할 때 WebApplicationContext로 만들어 재사용을 하고 이후 각각의 Batch Job에서 생성한 ApplicationContext와 parent/child 관계를 유지할 수 있도록 만들자는 것이 하나의 안이었습니다. 물론 Quartz와 Spring에 대한 통합도 하지 않고 현재의 구조를 최대한 유지하면서 Spring Batch로 단계적으로 전환하는 전략을 구사하고 있습니다.

물론 처음부터 모두 바꾸는 전략도 좋지만 정말 하고자하는 일이 Batch에 대한 모니터링이 가능한 환경을 구축하는 것이기 때문에 Spring Batch로 전환하는데 집중하기로 한 것입니다. 좋은 전략이라고 생각합니다. 이 시점에 정말 중요한 것은 Batch Job을 통일시키는 것이지 Scheduler를 변경하는 것은 아니기 때문입니다.

이 같은 요구사항을 만족시키기 위하여 ApplicationContext간의 parent/child 관계를 동적으로 만들고 Batch Job이 완료되면 parent/child 관계를 해제해야 상황이 발생했습니다. 이 문제에 대한 해결책을 찾기 위하여 검색해 봤는데 딱히 좋은 해결책이 없더군요. 그 동안 웹 애플리케이션을 개발할 때는 서블릿 컨테이너를 통하여 한번에 ApplicationContext를 생성했기 때문에 딱히 고민하지 않던 문제였으니까요. 그래서 Spring MVC를 사용할 때 parent/child 구조가 발생하기 때문에 가능하다고 생각했죠.

그래서 찾아보게 된 것이 ApplicationContext의 API내에 해결 방법이 있을 듯 하더군요. 그런데 의외로 쉽게 해결책을 찾았습니다. Spring API가 이미 잘 지원하고 있더라고요.

package net.javajigi.ac;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextLoadTest {
  @Test
  public void loadBeanFromChild() throws Exception {
    ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("parent.xml");
    ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[] {"child.xml"}, true, parent);
    
    Person person = child.getBean(Person.class);
    Address address = child.getBean(Address.class);
    assertNotNull(person);
    assertNotNull(address);
    child.close();
  }
}

Person과 Address의 초기화와 소멸되는 과정에 로깅을 하고 테스트 진행해 보면 결과를 확인할 수 있습니다. 테스트를 할 수 있도록 나머지 소스도 첨부하면 다음과 같습니다.

Person.java
package net.javajigi.ac;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

public class Person implements InitializingBean, DisposableBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("Person start!!");
  }

  public String getName() {
    return "name";
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("Person end!!");
  }
}
Address.java
package net.javajigi.ac;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Address implements InitializingBean, DisposableBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("Address start!!");
  }

  public String getCity() {
    return "yong in si";
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("Address end!!");
  }
}
parent.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="person" class="net.javajigi.ac.Person"/>
</beans>
child.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="address" class="net.javajigi.ac.Address"/>
</beans>
Posted at 17 3월 @ 9:49 오전 by 자바지기 | 0 Comments

3월 2010  
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

3월 13, 2010