J2EE 애플리케이션에서 정기적으로 예정된 백엔드 태스크를 실행할 필요가 종종 생긴다. 이는 자연적으로 타이머를 호출하게 된다. J2EE 1.4 이전에는, 엔터프라이즈 빈에 대한 타이머를 생성하는 것은 일반적으로 사용자 솔루션을 생성하거나, J2SE 타이머 기능을 재사용하거나 써드 파티 제품을 이용하는 것을 의미했다. 그러나 J2EE 1.4에서는 컨테이너가 관리하는 타이머 서비스를 제공한다. 이 서비스로 각각의 등록된 타이머가 유지되며, 타이머가 사용 종료되었을 때 엔터프라이즈 빈에 알려주게 된다. 컨테이너가 갑자기 멈추게 되었다면, 재시작할 때 타이머도 재생성된다. 어떤 타이머이던 사용 종료되면 이에 작용되는 엔터프라이즈 빈에 알려주게 된다.

엔터프라이즈 빈의 타이머 인터페이스 사용하기라는 제목의 2004년 6월 18일자 테크팁에서는 타이머가 종료되었을 때 로그를 지워주는 간단한 타이머 빈을 소개하고 있다. 여기서 "사용 종료"라는 의미는 타이머가 0까지 숫자 세기를 끝내고 엔터프라이즈 빈이 어떤 작업을 수행해야함을 통보하였음을 뜻한다. 더 이상 사용가능하지 않으므로 타이머 서비스로부터 폐기해야한다는 의미가 아니다(이것은 '타이머 삭제'임)

이번에 소개하는 테크팁에서는 세션 빈에서 간단한 타이머를 구현하는 데 필요한 소스 코드에 대해서 다시 한번 살펴보려고 한다. 이번 팁은 기존 팁을 토대로 하여 타이머로 작업할 때 필요한 몇 가지 고려사항에 대해 논의하며, 사용자가 배치와 로컬 빈 메소드를 포함하는 EJB 아키텍처에 대해 익숙하다고 가정한다.

타이머 아키텍처 다시보기

기초적인 것부터 되새겨보자. 엔터프라이즈 빈은 어떤 시간의 타이머이던지 생성할 수 있으며, 빈이 배치되는 EJB 환경이 이를 허용한다. 엔터티 빈에 의해 생성된 타이머는 빈의 주요 키 구분자(primary key identity)에 지정된다. 결과적으로 각각의 엔터티 빈의 인스턴스에 대한 타이머는 한 개뿐이다. 비상태 유지 세션 빈(stateless session beans)과 메시지 드리븐 빈(message-driven beans)에 의해 생성된 타이머는 컨테이너 풀의 인스턴스 사이에서 공유된다,.

다음은 EJB 2.1 아키텍처에서 타이머를 생성하는 네 개의 주요한 클래스와 인터페이스이다.

  • javax.ejb.TimedObject : 이 인터페이스는 엔터프라이즈 빈 설계시 반드시 구현되야하는 ejbTimeout() 메소드를 지정한다. 이 타이머 서비스는 각각의 타이머가 종료시 ejbTimeout() 메소드를 호출한다.
  • javax.ejb.TimerService : 이 클래스는 컨테이터의 타이머 서비스 오브젝트이다. TimerServiceSessionContextgetTimerService() 메소드를 통해 얻어진다.
  • javax.ejb.Timer : 사용자로 하여금 현재의 엔터프라이즈 빈에 속하는 타이머를 생성/삭제할 수 있게 하는 클래스이다. TimerTimerService 오브젝트의 createTimer() 메소드를 통해 생성된다.
  • javax.ejb.TimerHandle : 이 오브젝트는 Timer의 나열된 복사본을 제공한다. 이 복사본은 지속적인 타이머를 저장하고 검색하는 데 사용할 수 있다. TimerHandleTimer 오브젝트의 getHandle() 메소드에 의해 리턴된다.

EJB 타이머를 생성하는 것은 간단하며, 단지 두 가지 단계만 필요로 한다.

  1. javax.ejb.TimedObject 인터페이스를 확장하는 엔터프라이즈 빈(엔터티 빈, 비상태 유지 세션 빈 또는 메시지 드리븐 빈)을 생성한다. 이 인터페이스에서는 타이머가 종료되었을 때, ejbTimeout()로 불리는 메소드가 타이머 서비스에 의해 호출되야 한다.
  2. TimerService 오브젝트를 사용하여 타이머를 생성한다. TimerService 오브젝트의 인스턴스를 갖게되면 네 개의 createTimer() 메소드 중 하나를 사용하여 타이머를 서비스에 넣어야 한다. 이 메소드는 EJB 컨테이너 안의 타이머를 인스턴스화한다

이 때 네 개의 createTimer() 메소드는 다음과 같다.

  • createTimer(long timeoutDuration, Serializable info): 단일 작업 타이머를 생성한다. timeoutDuration 매개 변수는 시간의 크기를 밀리세컨드 단위로 지정하며, 이 변수는 타이머가 종료되어 TimedObjectejbTimeout() 콜백 메소드가 활성화되기 전에 전달하는 것이 허용된다.
  • createTimer(Date firstDate, Serializable info): 위의 메소드와 비슷한 방식으로 작용하지만 사용자가 종료시간을 설정하는 대신 타이머가 언제 사용되는지 지정하는 Date 객체를 제공해야한다.
  • createTimer(Date firstDate, long timeoutInterval, Serializable info): 타이머가 사용되어야 하는 처음 날짜를 지정한다. 또한 반복되는 각각의 타이머를 사용하는 간격 간의 시간도 지정한다.
  • createTimer(long timeoutDuration, long timeoutInterval, Serializableinfo): 이 메소드는 위의 간격 메소드와 비슷하다. 그러나 현재 시스템 시간으로부터 밀리세컨드 단위로 지정된 시간 간격에 기반하여 처음 사용이 이루어 진다는 것이 다르다.

createTimer() 메소드의 시간 간격 타이머 버전은 일정한 간격으로 반복적으로 일어나는 작업에, 단일 작업 버전은 한번 이용되고 폐기되는 타이머에 사용하기 바란다. 각각의 createTimer() 메소드에는 info라고 불리는 Serializable 매개 변수가 포함되어 있음을 주목하자. 이 매개변수는 타이머에 대한 식별 태그(일반적으로 String)을 전달하는 데 사용되며 이 식별 태그는 필요시 타이머 인스턴스를 나중 지점에 위치는 데 사용된다. Serializable 매개변수는 또한 타이머 콜백이 진행되는 동안 필요할지 모르는 오브젝트에 레퍼런스를 전달해주는 데에도 사용된다. 이 매개변수가 필요하지 않을 경우에는 null로 설정하면 된다.

타이머를 삭제하기 위해서는 지정 Timer 오브젝트에 cancel() 메소드를 사용하면 된다. 이 메소드는 현재의 타이머를 삭제한다.

다음은 타이머를 생성하고 제거하는 메소드를 포함하는 비상태 유지 세션 빈에 대한 예제이다.

   public class TimerBean implements SessionBean, TimedObject
   {

       //  EJB Framework Code Omitted
    
       public void createTimer(
          long startTime, long timeout, String id)
       throws javax.ejb.EJBException, java.rmi.RemoteException
       {
        
           TimerService timerService = 
              sessionContext.getTimerService();
           Timer timer = 
              timerService.createTimer(startTime, timeout, id);
       }
    
       public void killTimer(String id)
       throws javax.ejb.EJBException, java.rmi.RemoteException
       {
        
           TimerService timerService = 
              sessionContext.getTimerService();
           Collection timers = timerService.getTimers();
           Iterator iterator = timers.iterator();
        
           //  Search through the collection, and find the timer
           //  that matches the given ID. For each instance
           //  that is found, call the cancel() method on it.

           while (iterator.hasNext()){
               Timer t = (Timer)iterator.next();
               if (t.getInfo().equals(id))
                   t.cancel();
           }
        
       }

   }

타이머 작업 시 고려사항

타이머를 사용하는 엔터프라이즈 빈을 설계할 때 고려해야 할 몇 가지 중요한 사항에 대해서 설명하겠다.

  • 엔터티 빈과 비상태 유지 세션 빈, 메시지 드리븐 빈은 각각의 타이머 서비스를 보유하고 있으나 상태 유지 세션빈은 보유하고 있지 않다.(상태 유지 세션빈이 EJB 타이머에 전달되면 javax.ejb.Timer 작용을 활성화시킬 수는 있다.)
  • 엔터티 빈에서는 ejbPostCreate() 메서드로 타이머를 생성한다. 이 방법으로 타이머는 특정 빈 인스턴스에 수반될 수 있게 된다. 비상태 유지 세션 빈에서는 빈의 BM(business method)로 타이머를 생성하고, 메시지 드리븐 빈에서는 메시지가 수신될 때마다 타이머가 생성되어야 한다.
  • 각각의 createTimer() 메소드의 나열가능한 정보 매개변수를 기억한다. 이 매개변수는 한 빈에서 하나 이상의 타이머를 생성하고자 할 때 유용하다.
  • 나중에 이용할 TimerHandle 인스턴스를 나열하고 복구하기 위해 Timer 오브젝트의 getHandle() 메소드를 사용할 수 있다. TimerHandle를 deserialize한 후에는 타이머의 인스턴스를 다시 얻기 위해 getTimer() 메소드를 이용해야한다.
  • 타이머를 삭제하는 법을 아는 것도 종종 유용하나 단일 작업 타이머는 작업을 성공적으로 수행 후 종료되면 자동적으로 제거된다는 사실에 대해서도 기억해두길 바란다. 많은 애플리케이션에서는 지속적으로 사용할 수 있는 주기적 타이머가 사용되고 있다. 엔터티 빈에 포함되어있는 EJB 타이머는 엔터티 빈(주요 키)이 제거되면 자동적으로 삭제된다. 덧붙여 애플리케이션을 종료하면 모든 EJB 타이머는 삭제된다.
  • 엔터티 빈에는 일반적으로 각각의 인스턴스에 대한 타이머가 있다. 메시지 드리븐 빈과 비상태 유지 세션 빈은 특정 빈의 인스턴스가 아닌 각 타입의 빈과 조합되어 있다. 메시지 드리븐 빈 또는 비상태 유지 세션 빈의 타이머가 종료되면 컨테이너는 인스턴트 풀에 있는 단일 TimedObject 빈 인스턴스의 ejbTimeout() 메소드를 호출한다. 컨테이너는 어떤 인스턴스든지 선택할 수 있다.
  • createTimer()를 호출할 때마다 컨테이너 내부에는 매번 새로운 타이머 오브젝트가 생성된다. 이미 진행된 타이머를 재사용할 수 있다면 애플리케이션 서버에 타이머가 너무 많아지지 않도록 주의하기 바란다. 기존의 타이머를 체크하여 그 유일성을 보장하고 싶다면 타이머 서비스의 getTimers() 메소드를 이용하기 바란다. 이 메소드는 위의 예제에서의 killTimer() 메소드에서 보여주고 있다.
  • 트랜젝션에 타이머를 이용하고 있다면 반드시 ejbTimeout() 메소드에 RequiresNew의 트랜잭션 특징을 부여해야 한다. 타이머의 생성/삭제는 현재 빈의 컨텍스트에서 이뤄져야한다. 이 경우 트랙잭션이 복구되야한다면, 타이머의 생성/삭제 또한 복구된다.
  • 현재 많은 벤더들이 EJB 타이머를 관리하기 위해 JMX Mbeans을 제공하고 있다.

EJB 타이머 베스트 프랙티스에 대한 좀 더 많은 정보는 Java BluePrints Solutions Catalog의 Using the J2EE 1.4 Timer Service for Scheduling Actions 섹션을 참조하기 바란다. 타이머 설계에 대한 훌륭한 리소스가 될 것이다.

타이머를 실행해보고 싶다면 2004년도 6월 18일자 J2EE 테크팁 엔터프라이즈 빈의 타이머 인터페이스 사용하기샘플 아카이브를 다운받기 바란다.

또한 EJB 2.1 specification를 참조하자.

예제 코드 실행

예제 파일들을 다운로드 받으세요. 이 애플리케이션의 루트는 ttdec2004-jaxb이며, 다운로드된 war 파일에는 예제의 모든 소스 코드가 포함되어 있습니다.

애플리케이션 파일들(ttdec2004-jaxb)을 J2EE 1.4 애플리케이션 서버에 설치하려면 deploytool 프로그램 혹은 관리자 콘솔을 사용해야 합니다. 혹은 아래와 같이 asadmin 명령어를 입력하여 설치를 할 수도 있습니다.

   asadmin deploy install_dir/ttdec2004-jaxb.war

install_dir을 war 파일을 설치한 디렉토리로 대체하십시오.

애플리케이션은 http://localhost:8080/ttdec2004-jaxb를 통해서 접속할 수 있습니다.

J2EE 1.4 애플리케이션 서버 이외의 J2EE 1.4 호환 설치를 위해서는 J2EE 제품의 설치 툴을 사용하여 원하는 플랫폼에 애플리케이션을 설치하시기 바랍니다.

애플리케이션을 시작하면 아래와 같은 페이지가 나타납니다. (페이지 전체가 나타나 있지는 않습니다.)

"Click here to see the example servlet."라고 씌여있는 링크를 클릭하세요. JAXB 테스트 servlet이 구동되어 다음과 같은 표시가 나타납니다.

"Java EE" 카테고리의 다른 글

2005/02/03 16:03 2005/02/03 16:03

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/289

댓글을 달아 주세요

  1. 이우철  수정/삭제  댓글쓰기

    멋진 기능!! 꼭 필요한 기능!!
    감사합니다!!!

    2007/09/07 20:20
  2. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 05:34
[로그인][오픈아이디란?]

◀ Prev 1  ... 539 540 541 542 543 544 545 546 547  ... 626  Next ▶