±âŸ(framework)
2018.06.29 / 21:58

Job Scheduling in Java

aichatbot
Ãßõ ¼ö 231
by Dejan Bosanac
¹ø¿ª ÇãŸí
03/10/2004 


¾î¶² ÇÁ·ÎÁ§Æ®¿¡¼­ Á¤È®È÷ Á¤ÇØÁø ½Ã°£À̳ª ÀÏÁ¤ÇÑ ½Ã°£ °£°ÝÀ¸·Î ½ÇÇàµÇ´Â ÀÛ¾÷ÀÌ ÇÊ¿äÇÒ ¼ö ÀÖ´Ù. ÀÌ ±Û¿¡¼­ ¿ì¸®´Â ÀÚ¹Ù °³¹ßÀÚ°¡ Ç¥ÁØ Java Timer API¸¦ »ç¿ëÇÏ¿© ¾î¶»°Ô ÀÌ·¯ÇÑ ¿ä±¸»çÇ×À» ±¸ÇöÇÒ ¼ö ÀÖ´ÂÁö »ìÆ캼 °ÍÀÌ´Ù. ±×¸®°í, Java Timer API°¡ Á¦°øÇÏ´Â ±âº»ÀûÀÎ ½ºÄÉÁ층 ½Ã½ºÅÛ ¿Ü¿¡ Ãß°¡ÀûÀÎ ±â´ÉÀ» ÇÊ¿ä·Î ÇÏ´Â »ç¶÷À» À§ÇØ ¿ÀÇ ¼Ò½º ¶óÀ̺귯¸®ÀÎ Quartz¿¡ ´ëÇØ »ìÆ캼 °ÍÀÌ´Ù.

¸ÕÀú ½ºÄÉÁ층 ÀÛ¾÷À» ÇÊ¿ä·Î ÇÒ ¶§, ÀÌ·¯ÇÑ »óȲÀ» ÀνÄÇϴµ¥ µµ¿òÀ» ÁÙ ¼ö ÀÖ´Â ÀϹÝÀûÀÎ À¯½ºÄÉÀ̽º¿¡ ´ëÇؼ­ ¸î °¡Áö »ìÆ캸ÀÚ. ±×¸®°í ³ª¼­ ¿ì¸®´Â ¿©·¯ºÐÀÇ ±â´ÉÀû ¿ä±¸¿¡ °¡Àå ¾Ë¸Â´Â ÃÖ¼±ÀÇ ÇØ°áÃ¥À» ã¾Æ º¼ °ÍÀÌ´Ù.

´ëºÎºÐÀÇ ºñÁö´Ï½º ¾ÖÇø®ÄÉÀ̼ÇÀº À¯ÀúµéÀÌ ÇÊ¿ä·Î ÇÏ´Â º¸°í¼­¿Í Åë°è¸¦ °¡Áö°í ÀÖ´Ù. ½Ã½ºÅÛ¿¡ ÅõÀÚÇÏ´Â »ç¶÷µéÀÇ ÀϹÝÀûÀÎ ¸ñÀûÀº ´ë·®ÀÇ µ¥ÀÌÅ͸¦ ¼öÁýÇÏ°í ±×°ÍÀ» ¹Ì·¡ÀÇ ºñÁö´Ï½º °èȹÀ» ¼¼¿ì´Âµ¥ µµ¿òÀÌ µÇ´Â ¹æ½ÄÀ¸·Î º¸´Â °ÍÀ̱⠶§¹®¿¡, ÀÌ·¯ÇÑ ÀÏÀ» °¡´ÉÇÏ°Ô ÇØÁÖ´Â º¸°í¼­°¡ ¾ø´Â ½Ã½ºÅÛÀº »ó»óÇϱâ Èûµé´Ù. ÀÌ·¯ÇÑ º¸°í¼­¸¦ »ý¼ºÇϴµ¥ À־ÀÇ ¹®Á¦Á¡Àº ó¸®ÇؾßÇÒ µ¥ÀÌÅÍÀÇ ¾çÀÌ ´ë·®À̱⠶§¹®¿¡, ÀϹÝÀûÀ¸·Î µ¥ÀÌÅͺ£À̽º ½Ã½ºÅÛ¿¡ Å« ºÎÇÏ°¡ °É¸°´Ù´Â °ÍÀÌ´Ù. ÀÌ·¯ÇÑ ºÎÇÏ´Â ½Ã½ºÅÛÀÌ º¸°í¼­¸¦ »ý¼ºÇÏ´Â µ¿¾È, ÀüüÀûÀÎ ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¼º´ÉÀ» ¶³¾î¶ß¸®°í ´ÜÁö µ¥ÀÌÅÍ ¼öÁýÀ» À§ÇÏ¿© ½Ã½ºÅÛÀ» »ç¿ëÇÏ´Â À¯Àú¿¡°Ôµµ ¿µÇâÀ» ³¢Ä£´Ù. ¶ÇÇÑ À¯ÀúÀÔÀå¿¡¼­ »ý°¢ÇÑ´Ù¸é, »ý¼ºÇϴµ¥ 10ºÐÀÌ °É¸®´Â º¸°í¼­´Â ÁÁÀº ÀÀ´ä½Ã°£ÀÇ ¿¹°¡ ¾Æ´Ï´Ù.

¿ì¸®´Â ¸ÕÀú ½Ç½Ã°£À¸·Î ½ÇÇàµÉ ÇÊ¿ä°¡ ¾ø´Â, ij½¬µÉ ¼ö ÀÖ´Â Á¾·ùÀÇ º¸°í¼­¿¡ ´ëÇØ »ìÆ캼 °ÍÀÌ´Ù. ±â»Ú°Ôµµ ´ëºÎºÐÀÇ º¸°í¼­°¡ ÀÌ·¯ÇÑ ºÎ·ù¿¡ µé¾î°£´Ù. -- ÀÛ³â 6¿ùÀÇ ¾î¶² Á¦Ç° ÆǸſ¡ °üÇÑ Åë°è, ¶Ç´Â 1¿ùÀÇ È¸»ç ¼Òµæ µî. ÀÌ·¯ÇÑ Ä³½¬°¡ °¡´ÉÇÑ º¸°í¼­´Â °£´ÜÇÑ ¹æ¹ýÀ¸·Î ÇØ°áÇÒ ¼ö ÀÖ´Ù : ½Ã½ºÅÛÀÌ ÇÑ°¡ÇÒ ¶§ ¶Ç´Â µ¥ÀÌÅͺ£À̽º ½Ã½ºÅÛÀÇ ºÎÇÏ°¡ ÃÖ¼ÒÀÏ ¶§, º¸°í¼­¸¦ »ý¼ºÇϵµ·Ï ½ºÄÉÁ층ÇÏ¸é µÈ´Ù. ¿©·¯ºÐÀÌ ¸¹Àº »ç¹«½Ç(¸ðµÎ °°Àº ½Ã°£´ë¿¡ ÀÖ´Â)À» °¡Áö°í ÀÖ´Â Áö¿ª Ã¥ ÆǸÅÀÚ¸¦ À§ÇÑ ¾ÖÇø®ÄÉÀ̼ÇÀ» ¸¸µç´Ù°í Çغ¸ÀÚ. ¿©·¯ºÐÀº ÁÖ´ç ¼Òµæ¿¡ ´ëÇÑ º¸°í¼­(¾Æ¸¶µµ ´ë·®ÀÇ)¸¦ »ý¼ºÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ¸ÅÁÖ ÀÏ¿äÀÏ ¹ã°ú °°ÀÌ ½Ã½ºÅÛÀÌ »ç¿ëµÇÁö ¾Ê´Â ½Ã°£¿¡ µ¥ÀÌÅͺ£À̽º¿¡ ij½¬Çؼ­ ÀÌ·¯ÇÑ ÀÛ¾÷À» ½ºÄÉÁ층 ÇÒ ¼ö ÀÖ´Ù. ÀÌ·¯ÇÑ ¹æ½ÄÀ¸·Î ±¸ÇöÇϸé, ÆǸŠ´ã´çÀÚ´Â ¿©·¯ºÐÀÇ ¾ÖÇø®ÄÉÀ̼ǿ¡¼­ ¼º´É»óÀÇ ¹®Á¦Á¡À» ãÁö ¸øÇÒ °ÍÀÌ´Ù. ±×¸®°í ȸ»ç °ü¸®ºÎ´Â ÇÊ¿äÇÑ ¸ðµç µ¥ÀÌÅ͸¦ ºü¸¥ ½Ã°£¿¡ ±¸ÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

´ÙÀ½À¸·Î ´Ù·ê µÎ¹ø° ¿¹Á¦´Â °èÁ¤ »ç¿ë±âÇÑ ¸¸·á¿Í °°Àº ÀÏ·ÃÀÇ °øÁö(notification)¸¦ ¾ÖÇø®ÄÉÀÌ¼Ç À¯Àú¿¡°Ô º¸³»´Â ÀÛ¾÷¿¡ °üÇÑ °ÍÀÌ´Ù. ÀÌ°ÍÀº À¯Àú µ¥ÀÌÅÍ¿¡¼­ ³¯Â¥ Çʵ带 »ç¿ëÇÏ¿© À¯ÀúÀÇ Á¶°ÇÀ» °Ë»çÇÏ´Â ¾²·¹µå¸¦ »ý¼ºÇÔÀ¸·Î½á ÇàÇØÁú ¼ö ÀÖ´Ù. ±×·¯³ª ÀÌ·¯ÇÑ °æ¿ì ½ºÄÉÁì·¯¸¦ »ç¿ëÇÏ´Â °ÍÀÌ ¸í¹éÇÏ°Ô ´õ¿í ¿ì¾ÆÇÑ ÇØ°áÃ¥ÀÌ°í, ÀüüÀûÀÎ ½Ã½ºÅÛ ¾ÆÅ°ÅØÃÄ(¾ÆÅ°ÅØÃÄ´Â Áß¿äÇÏ´Ù. ±×·¸Áö ¾ÊÀº°¡?)ÀÇ Ãø¸é¿¡¼­µµ ´õ ÁÁ´Ù. º¹ÀâÇÑ ½Ã½ºÅÛ¿¡¼­ ¿©·¯ºÐÀº ÀÌ·¯ÇÑ Á¾·ùÀÇ °øÁö¸¦ ¸¹ÀÌ °¡Áö°í ÀÖÀ» °ÍÀÌ°í, ÀÌ¿ÜÀÇ ´Ù¸¥ ¸¹Àº °æ¿ì¿¡µµ ¶ÇÇÑ ½ºÄÉÁì·¯ ½Ã½ºÅÛÀÌ ÇÊ¿äÇÒ °ÍÀÌ´Ù. µû¶ó¼­, ½ºÄÉÁ층 ÀÛ¾÷À» ÇÊ¿ä·Î ÇÏ´Â °¢°¢ÀÇ °æ¿ì¿¡ ´ëÇØ ÇØ°áÃ¥À» ±¸ÇöÇÏ´Â °ÍÀº ½Ã½ºÅÛÀ» º¯°æÇÏ°í À¯Áöº¸¼öÇÏ´Â °ÍÀ» ´õ¿í ¾î·Æ°Ô ÇÒ °ÍÀÌ´Ù. ÀÏÀÏÀÌ ½ºÄÉÁ층 ÀÛ¾÷À» ±¸ÇöÇÏ´Â ´ë½Å ¿©·¯ºÐÀº ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¸ðµç ½ºÄÉÁ층À» ´ã´çÇÏ´Â API¸¦ »ç¿ëÇؾ߸¸ ÇÑ´Ù. ÀÌ°ÍÀÌ ÀÌ ±ÛÀÇ ³ª¸ÓÁö ºÎºÐ¿¡¼­ ´Ù·ç´Â ÁÖÁ¦ÀÌ´Ù.

°£´ÜÇÑ ÇØ°áÃ¥
ÀÚ¹Ù ¾ÖÇø®ÄÉÀ̼ǿ¡ ±âº»ÀûÀÎ ½ºÄÉÁì·¯¸¦ ±¸ÇöÇϱâ À§ÇØ ¿©·¯ºÐÀº ¾î¶² ¿ÜºÎ ¶óÀ̺귯¸®µµ ÇÊ¿ä ¾ø´Ù. J2SE 1.3 ÀÌÈÄ·Î ÀÚ¹Ù´Â ÀÌ·¯ÇÑ ¸ñÀûÀ¸·Î »ç¿ëµÉ ¼ö ÀÖ´Â java.util.Timer, java.util.TimerTask µÎ °³ÀÇ Å¬·¡½º¸¦ Æ÷ÇÔÇÏ°í ÀÖ´Ù. ¸ÕÀú ÀÌ API·Î °¡´ÉÇÑ ¸ðµç °ÍÀ» ¼³¸íÇØÁÖ´Â °£´ÜÇÑ ¿¹Á¦¸¦ ¸¸µé¾îº¸ÀÚ.

package net.nighttale.scheduling;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ReportGenerator extends TimerTask {

  public void run() {
    System.out.println("Generating report");
    //TODO generate report
  }

}

class MainApplication {

  public static void main(String[] args) {
    Timer timer  new Timer();
    Calendar date = Calendar.getInstance();
    date.set(
      Calendar.DAY_OF_WEEK,
      Calendar.SUNDAY
    );
    date.set(Calendar.HOUR, 0);
    date.set(Calendar.MINUTE, 0);
    date.set(Calendar.SECOND, 0);
    date.set(Calendar.MILLISECOND, 0);
    // Schedule to run every Sunday in midnight
    timer.schedule(
      new ReportGenerator(),
      date.getTime(),
      1000 * 60 * 60 * 24 * 7
    );
  }
}
ÀÌ ±ÛÀÇ ¸ðµç ¿¹Á¦ ÄÚµå´Â ±Û ¸»¹ÌÀÇ ¸µÅ©¿¡¼­ ´Ù¿î·Îµå ¹ÞÀ» ¼ö ÀÖ´Ù.

À§ÀÇ ÄÚµå´Â ¼­µÎ¿¡¼­ ¾ð±ÞÇÑ, ½Ã½ºÅÛÀÌ ÇÑ°¡ÇÑ ½Ã°£(¿¹Á¦ÀÇ °æ¿ì ÀÏ¿äÀÏ ¹ã)¿¡ º¸°í¼­¸¦ »ý¼ºÇϵµ·Ï ½ºÄÉÁ층ÇÏ´Â ¿¹Á¦¸¦ ±¸ÇöÇÏ°í ÀÖ´Ù.

¸ÕÀú ¿ì¸®´Â ½ÇÁ¦·Î ½ºÄÉÁ층µÈ ÀÛ¾÷À» ¼öÇàÇÏ´Â "worker" Ŭ·¡½º¸¦ ±¸ÇöÇØ¾ß ÇÑ´Ù. ¿ì¸®ÀÇ ¿¹Á¦¿¡¼­ ÀÌ°ÍÀº ReportGenerator ÀÌ´Ù. ÀÌ Å¬·¡½º´Â java.lang.RunnableÀ» ±¸ÇöÇÏ´Â java.util.TimerTask Ŭ·¡½º¸¦ »ó¼Ó¹Þ¾Æ¾ß ÇÑ´Ù. ±×¸®°í ³ª¸ÓÁö ÇÒ ÀÏÀº º¸°í¼­¸¦ »ý¼ºÇÏ´Â Äڵ带 run() ¸Þ¼Òµå ¾È¿¡ ¿À¹ö¶óÀ̵åÇÏ´Â °Í ¹Û¿¡ ¾ø´Ù.

¿ì¸®´Â ÀÌ °´Ã¼ÀÇ ½ÇÇàÀ» Timer Ŭ·¡½ºÀÇ ½ºÄÉÁ층 ¸Þ¼Òµå ÁßÀÇ Çϳª¸¦ ÀÌ¿ëÇؼ­ ½ºÄÉÁ층ÇÑ´Ù. ¿¹Á¦ÀÇ °æ¿ì ÃÖÃÊ ½ÇÇà ³¯Â¥¿Í ¹Ð¸®¼¼ÄÁµå ´ÜÀ§ÀÇ ½ÇÇà Áֱ⸦ ÀÎÀÚ·Î ¹Þ¾ÆµéÀÌ´Â schedule() ¸Þ¼Òµå¸¦ »ç¿ëÇÑ´Ù.(¿Ö³ÄÇÏ¸é ¿ì¸®´Â ÀÌ º¸°í¼­¸¦ ¸ÅÁÖ »ý¼ºÇÒ °ÍÀ̱⠶§¹®ÀÌ´Ù.)

½ºÄÉÁ층 ±â´ÉÀ» »ç¿ëÇÒ ¶§, ¿ì¸®´Â ½ºÄÉÁ층 API°¡ Á¦°øÇÏ´Â ¸®¾óŸÀÓ¿¡ ´ëÇÑ º¸ÁõÀ» ¾Ë¾Æ¾ß¸¸ ÇÑ´Ù. ºÒÇàÇÏ°Ôµµ ÀÚ¹ÙÀÇ Æ¯¼º°ú ´Ù¾çÇÑ Ç÷§Æû¿¡¼­ÀÇ ±¸Çö¶§¹®¿¡, °¢°¢ÀÇ JVM¿¡¼­ÀÇ ¾²·¹µå ½ºÄÉÁ층ÀÇ ±¸ÇöÀº ÀÏÄ¡ÇÏÁö ¾Ê´Â´Ù. ±×·¯¹Ç·Î, Timer´Â ¿ì¸®ÀÇ ½ºÄÉÁ층 ÀÛ¾÷ÀÌ Á¤È®ÇÑ ±ÔÁ¤µÈ ½Ã°£¿¡ ½ÇÇàµÉ °ÍÀ̶ó°í º¸ÁõÇÒ ¼ö ¾ø´Ù. ¿ì¸®ÀÇ ½ºÄÉÁ층 ÀÛ¾÷Àº Runnable °´Ã¼·Î ±¸ÇöµÇ¾î ÀÖ°í ¶§¶§·Î ÀÏÁ¤ ½Ã°£µ¿¾È sleep »óÅ°¡ µÈ´Ù. ±×·¯¸é Timer´Â ±ÔÁ¤µÈ ¼ø°£¿¡ À̵éÀ» ±ú¿î´Ù. ±×·¯³ª Á¤È®ÇÑ ½ÇÇà ½Ã°£Àº JVMÀÇ ½ºÄÉÁ층 Á¤Ã¥°ú ÇöÀç ¾ó¸¶³ª ¸¹Àº ¾²·¹µå°¡ ÇÁ·Î¼¼¼­¸¦ ±â´Ù¸®°í ÀÖ´À³Ä¿¡ µû¶ó ´Þ¶óÁø´Ù. ¿ì¸®ÀÇ ½ºÄÉÁ층 ÀÛ¾÷ ½ÇÇàÀ» Áö¿¬½Ãų ¼ö ÀÖ´Â µÎ °¡Áö ÀϹÝÀûÀÎ °æ¿ì°¡ ÀÖ´Ù. ù°, ¸¹Àº ¼öÀÇ ¾²·¹µå°¡ ½ÇÇàµÇ±â¸¦ ±â´Ù¸®°í ÀÖ´Â °æ¿ìÀÌ´Ù; µÑ°, °¡ºñÁö ÄÝ·º¼ÇÀÇ È°µ¿¿¡ ÀÇÇØ Áö¿¬µÇ´Â °æ¿ì°¡ ÀÖ´Ù. ÀÌ·¯ÇÑ ¿µÇâµéÀº ´Ù¸¥ JVM¿¡¼­ ½ºÄÉÁì·¯¸¦ ½ÇÇà ¶Ç´Â °¡ºñÁö ÄÝ·ºÅÍÀÇ ¿É¼Ç Æ©´×°ú °°Àº ¿©·¯°¡Áö ±â¹ýÀ» »ç¿ëÇÔÀ¸·Î½á ÃÖ¼ÒÈ­µÉ ¼ö ÀÖ´Ù. ±×·¯³ª ±×°ÍÀº ÀÌ ±ÛÀÇ ÁÖÁ¦¸¦ ¹þ¾î³ª´Â °ÍÀÌ´Ù.

´Ù½Ã º»·ÐÀ¸·Î µ¹¾Æ¿ÀÀÚ. Timer Ŭ·¡½º¿¡´Â µÎ °³ÀÇ ´Ù¸¥ ½ºÄÉÁ층 ¸Þ¼Òµå ±×·ìÀÌ ÀÖ´Ù: °íÁ¤µÈ µô·¹ÀÌ·Î ½ºÄÉÁ층ÇÏ´Â schedule() ¸Þ¼Òµå¿Í °íÁ¤µÈ ºñÀ²·Î ½ºÄÉÁ층ÇÏ´Â scheduleFixedRate() ¸Þ¼Òµå°¡ ±×°ÍÀÌ´Ù. ù¹ø° ±×·ìÀÇ ¸Þ¼ÒµåµéÀ» »ç¿ëÇÒ ¶§, °¢ ÀÛ¾÷ ½ÇÇàÀÇ µô·¹ÀÌ´Â ´ÙÀ½ ÀÛ¾÷ ½ÇÇàÀ¸·Î Àü´ÞµÉ °ÍÀÌ´Ù. ÈÄÀÚ ±×·ìÀÇ °æ¿ì µô·¹À̸¦ ÃÖ¼ÒÈ­Çϸ鼭 ¸ðµç ¿¬¼ÓµÈ ÀÛ¾÷ ½ÇÇàÀº ÃÖÃÊ ÀÛ¾÷ ½ÇÇàÀÇ ½Ã°£¿¡ ¸ÂÃç ½ºÄÉÁ층 µÉ °ÍÀÌ´Ù. ¾î¶² ¸Þ¼Òµå¸¦ »ç¿ëÇÏ´À³Ä´Â ¿©·¯ºÐÀÇ ½Ã½ºÅÛ¿¡ ¾î¶² ÆĶó¹ÌÅÍ°¡ ´õ Áß¿äÇÏ´À³Ä¿¡ ´Þ·Á ÀÖ´Ù.

¸Å¿ì Áß¿äÇÑ °ÍÀÌ ÇÑ °¡Áö ´õ ÀÖ´Ù: °¢ Timer °´Ã¼´Â ¾²·¹µå¸¦ ¹é±×¶ó¿îµå·Î ½ÃÀÛÇÑ´Ù. ÀÌ·¯ÇÑ ¹æ½ÄÀº J2EE ¾ÖÇø®ÄÉÀÌ¼Ç ¼­¹ö¿Í °°Àº ȯ°æ¿¡¼­´Â ¹Ù¶÷Á÷ÇÏÁö ¾ÊÀ» °ÍÀÌ´Ù. ¿Ö³ÄÇϸé ÀÌ·¯ÇÑ ¾²·¹µåµéÀÌ ÄÁÅ×ÀÌ³Ê ¿µ¿ª ³»¿¡ ÀÖÁö ¾Ê±â ¶§¹®ÀÌ´Ù.


Æò¹üÇÑ °ÍÀ» ³Ñ¾î¼­
Áö±Ý±îÁö ¾ÖÇø®ÄÉÀ̼ǿ¡¼­ ¾î¶»°Ô ½ºÄÉÁ층À» ÇÏ´ÂÁö »ìÆì º¸¾Ò°í, ÀÌ°ÍÀº °£´ÜÇÑ ¿ä±¸»çÇ׿¡¼­´Â ÃæºÐÇÏ´Ù. ±×·¯³ª °í±Þ À¯Àú¿Í º¹ÀâÇÑ ¿ä±¸»çÇ×À» À§Çؼ­´Â À¯¿ëÇÑ ½ºÄÉÁ층À» Áö¿øÇϱâ À§ÇØ ´õ ¸¹Àº ±â´ÉµéÀ» ÇÊ¿ä·Î ÇÑ´Ù. ÀÌ·¯ÇÑ °æ¿ì µÎ °¡Áö ÀϹÝÀûÀÎ ÇØ°áÃ¥ÀÌ ÀÖ´Ù. ù¹ø°´Â ÀÚ½ÅÀÌ ÇÊ¿ä·Î ÇÏ´Â ±â´ÉÀ» °¡Áö°í ÀÖ´Â ½ºÄÉÁì·¯¸¦ ¸¸µå´Â °ÍÀÌ´Ù; µÎ¹ø°´Â ÇÊ¿ä·Î ÇÏ´Â ¿ä±¸»çÇ×À» ÃæÁ·ÇÏ´Â ÇÁ·ÎÁ§Æ®¸¦ ã¾Æ³»´Â °ÍÀÌ´Ù. ½Ã°£°ú ÀÚ¿øÀ» Àý¾àÇÒ ¼ö ÀÖ°í ´Ù¸¥ ´©±º°¡ÀÇ ³ë·ÂÀ» Áߺ¹ÇØ¾ß ÇÒ ÇÊ¿ä°¡ ¾ø±â ¶§¹®¿¡, µÎ¹ø° ÇØ°áÃ¥ÀÌ ´ëºÎºÐÀÇ °æ¿ì¿¡ À־ ´õ¿í ÀûÇÕÇÒ °ÍÀÌ´Ù.

ÀÌ·¯ÇÑ ¿ä±¸»çÇ×Àº ¿ì¸®¸¦ ´Ü¼øÇÑ Timer API ÀÌ»óÀÇ ÈξÀ ¶Ù¾î³­ ÀåÁ¡µéÀ» °¡Áø ¿ÀÇ ¼Ò½º ÀÛ¾÷ ½ºÄÉÁ층 ½Ã½ºÅÛÀÎ Quartz ·Î À¯µµÇÑ´Ù.

QuartzÀÇ Ã¹¹ø° ÀåÁ¡Àº ¿µ¼Ó¼ºÀÌ´Ù. ¸¸¾à ¿©·¯ºÐÀÇ ÀÛ¾÷ÀÌ ¾Õ¼­ÀÇ ¿¹Á¦¿Í °°ÀÌ "Á¤Àû"À̶ó¸é ¿µ¼Ó¼º Áö¿øÀº ÇÊ¿ä ¾øÀ» °ÍÀÌ´Ù. ±×·¯³ª Á¾Á¾ ¾î¶² Á¶°ÇÀÌ ÃæÁ·µÆÀ» ¶§ "µ¿Àû"À¸·Î ¼öÇàµÇ´Â ÀÛ¾÷À» ÇÊ¿ä·Î ÇÒ ¶§µµ ÀÖ´Ù. ±×¸®°í ÀÌ·¯ÇÑ ÀÛ¾÷µéÀÌ ½Ã½ºÅÛ Àç½ÃÀÛ(¶Ç´Â ½Ã½ºÅÛ ´Ù¿î) »çÀÌ¿¡µµ ½ÇÇàµÇ¾ß ÇÒ ¶§°¡ ÀÖ´Ù. Quartz´Â ºñ ¿µ¼Ó¼º°ú ¿µ¼Ó¼º ÀÛ¾÷ ¸ðµÎ¸¦ Á¦°øÇÑ´Ù. ¿µ¼Ó¼º ÀÛ¾÷ÀÇ »óÅ´ µ¥ÀÌÅͺ£À̽º¿¡ ÀúÀåµÉ °ÍÀÌ´Ù. µû¶ó¼­ ÀÌ·¯ÇÑ ÀÛ¾÷µéÀÌ ½ÇÇàµÇÁö ¾Ê´Â °æ¿ì°¡ ¾øÀ» °Å¶ó°í È®½ÅÇÒ ¼ö ÀÖ´Ù. ¿µ¼Ó¼º ÀÛ¾÷Àº ½Ã½ºÅÛ¿¡ Ãß°¡ÀûÀÎ ¼º´É °¨¼Ò¸¦ À¯¹ßÇϱ⠶§¹®¿¡ ÁÖÀDZí°Ô »ç¿ëÇؾ߸¸ ÇÑ´Ù.

Timer API´Â ¿øÇÏ´Â ½ÇÇà½Ã°£À» ´Ü¼øÇÏ°Ô ¼³Á¤ÇÒ ¼ö ÀÖ´Â ¸Þ¼Òµå°¡ ºÎÁ·ÇÏ´Ù. À§ ¿¹Á¦¿¡¼­ º» ´ë·Î, ½ÇÇà½Ã°£À» ¼³Á¤Çϱâ À§Çؼ­ ÇÒ ¼ö ÀÖ´Â °ÍÀº ½ÃÀÛÀÏÀÚ¿Í ¹Ýº¹Áֱ⸦ ¼³Á¤ÇÏ´Â °Í ¹Û¿¡ ¾ø´Ù. ºÐ¸íÈ÷, À¯´Ð½ºÀÇ cronÀ» »ç¿ëÇØ º» »ç¶÷µéÀº ½ºÄÉÁì·¯¸¦ ±×¿Í À¯»çÇÏ°Ô ¼³Á¤ÇÒ ¼ö Àֱ⸦ ¹Ù¶ö °ÍÀÌ´Ù. Quartz´Â ¿øÇÏ´Â ½Ã°£, ³¯Â¥¸¦ À¯¿¬ÇÑ ¹æ¹ýÀ¸·Î ¼³Á¤ÇÒ ¼ö ÀÖ°Ô ÇØÁÖ´Â org.quartz.CronTrigger¸¦ Á¤ÀÇÇÏ°í ÀÖ´Ù.

°³¹ßÀÚ´Â ÀÚÁÖ ÇÑ °¡Áö ÀÌ»óÀÇ ±â´ÉÀ» ÇÊ¿ä·Î ÇÑ´Ù: ÀÛ¾÷ÀÇ À̸§¿¡ ÀÇÇÑ ÀÛ¾÷ÀÇ °ü¸®¿Í Á¶Á÷È­. Quartz¿¡¼­ ´ç½ÅÀº À̸§À̳ª ±×·ì¿¡ ÀÇÇØ ¿øÇÏ´Â ÀÛ¾÷À» ã¾Æ³¾ ¼ö ÀÖ´Ù. ÀÌ°ÍÀº ½ºÄÉÁìµÈ ÀÛ¾÷ÀÌ ¸¹Àº ȯ°æ¿¡¼­ Å« µµ¿òÀÌ µÉ °ÍÀÌ´Ù.

ÀÌÁ¦ º¸°í¼­ »ý¼º ¿¹Á¦¸¦ Quartz¸¦ »ç¿ëÇÏ¿© ±¸ÇöÇÏ°í ¶óÀ̺귯¸®ÀÇ ±âº»ÀûÀÎ ±â´Éµé¿¡ ´ëÇØ ¼³¸íÇÒ °ÍÀÌ´Ù.

package net.nighttale.scheduling;

import org.quartz.*;

public class QuartzReport implements Job {

  public void execute(JobExecutionContext cntxt)
    throws JobExecutionException {
      System.out.println(
        "Generating report - " +
cntxt.getJobDetail().getJobDataMap().get("type")
      );
      //TODO Generate report
  }

  public static void main(String[] args) {
    try {
      SchedulerFactory schedFact 
       new org.quartz.impl.StdSchedulerFactory();
      Scheduler sched  schedFact.getScheduler();
      sched.start();
      JobDetail jobDetail 
        new JobDetail(
          "Income Report",
          "Report Generation",
          QuartzReport.class
        );
      jobDetail.getJobDataMap().put(
                                "type",
                                "FULL"
                               );
      CronTrigger trigger  new CronTrigger(
        "Income Report",
        "Report Generation"
      );
      trigger.setCronExpression(
        "0 0 12 ? * SUN"
      );
      sched.scheduleJob(jobDetail, trigger);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Quartz´Â Job, Trigger¶ó´Â µÎ °³ÀÇ ±âº» Ãß»ó °èÃþÀ» Á¤ÀÇÇÑ´Ù. JobÀº ½ÇÁ¦ ½ÇÇàµÇ´Â ÀÛ¾÷ÀÇ Ãß»ó °èÃþÀÌ°í, Trigger´Â ¾ðÁ¦ ÀÛ¾÷ÀÌ ½ÇÇàµÇ¾î¾ß ÇÏ´ÂÁö¸¦ ³ªÅ¸³»´Â Ãß»ó °èÃþÀÌ´Ù.

JobÀº ÀÎÅÍÆäÀ̽ºÀÌ´Ù. ±×·¡¼­ ¿ì¸®°¡ ÇؾßÇÒ ÀÏÀº Ŭ·¡½º°¡ org.quartz.Job(¶Ç´Â ³ªÁß¿¡ »ìÆ캸°Ô µÉ org.quartz.StatefulJob) ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇϵµ·Ï ÇÏ°í execute() ¸Þ¼Òµå¸¦ ¿À¹ö¶óÀ̵åÇÏ´Â °Í »ÓÀÌ´Ù. ¿¹Á¦¿¡¼­ java.util.MapÀÇ º¯ÇüµÈ ±¸ÇöÀÎ jobDataMap ¾îÆ®¸®ºäÆ®¸¦ ÅëÇØ ¾î¶»°Ô Job¿¡°Ô ÆĶó¹ÌÅ͸¦ Àü´ÞÇÒ ¼ö ÀÖ´ÂÁö »ìÆì ºÃ´Ù. »óÅ°¡ ÀÖ´Â ÀÛ¾÷, ¶Ç´Â ºñ »óÅ ÀÛ¾÷ Áß ¾î¶² °ÍÀ» ±¸ÇöÇÏ´À³Ä °áÁ¤ÇÏ´Â °ÍÀº ½ºÄÉÁ층 ÀÛ¾÷ÀÇ ½ÇÇൿ¾È ÀÌ·¯ÇÑ ÆĶó¹ÌÅ͵éÀ» º¯°æÇϱ⸦ ¿øÇÏ´À³Ä ¾Æ´Ï³Ä¸¦ °áÁ¤ÇÏ´Â ¹®Á¦ÀÌ´Ù. Job ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇÑ´Ù¸é ¸ðµç ÆĶó¹ÌÅ͵éÀº ÀÛ¾÷ÀÌ ÃÖÃÊ·Î ½ºÄÉÁ층 µÇ´Â ¼ø°£¿¡ ÀúÀåµÈ´Ù. ±×¸®°í ÀÌÈÄÀÇ º¯°æÀº ¸ðµÎ ¹ö·ÁÁø´Ù. execute() ¸Þ¼Òµå ³»¿¡¼­ StatefulJobÀÇ ÆĶó¹ÌÅ͸¦ º¯°æÇÑ´Ù¸é, ÀÛ¾÷ÀÌ ´ÙÀ½¿¡ »õ·Î ½ºÄÉÁ층 µÉ ¶§ ÀÌ »õ·Î¿î °ªÀÌ Àü´ÞµÉ °ÍÀÌ´Ù. °í·ÁÇؾßÇÒ ÇÑ °¡Áö Áß¿äÇÑ »çÇ×Àº StatefulJob ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇÑ ÀÛ¾÷µéÀº ½ÇÇàµÇ´Â µ¿¾È ÀÎÀÚµéÀÌ º¯ÇÒ ¼ö Àֱ⠶§¹®¿¡ µ¿½Ã¿¡ ½ÇÇàµÉ ¼ö ¾ø´Ù´Â °ÍÀÌ´Ù.

Trigger¿¡´Â µÎ °¡ÁöÀÇ ±âº»ÀûÀÎ Trigger°¡ ÀÖ´Ù: SimpleTrigger ¿Í CronTrigger. SimpleTrigger´Â ±âº»ÀûÀ¸·Î Timer API°¡ Á¦°øÇÏ´Â °Í°ú °°Àº ±â´ÉÀ» Á¦°øÇÑ´Ù. ÀÛ¾÷ÀÌ ½ÃÀÛµÈ ÀÌÈÄ¿¡ Á¤ÇØÁø °£°ÝÀ¸·Î ¹Ýº¹Çؼ­ ½ÇÇàµÇ´Â °æ¿ì, SimpleTrigger¸¦ ½á¾ß ÇÑ´Ù. SimpleTrigger´Â ½ÃÀÛÀÏ, Á¾·áÀÏ, ¹Ýº¹È½¼ö, ½ÇÇà Áֱ⸦ Á¤ÀÇÇÒ ¼ö ÀÖ´Ù.

À§ÀÇ ¿¹Á¦¿¡¼­´Â ´õ¿í »ç½ÇÀûÀÎ ¹ÙÅÁ¿¡¼­ ÀÛ¾÷À» ½ºÄÉÁ층ÇÒ ¼ö ÀÖ´Â À¯¿¬¼º¶§¹®¿¡ CronTrigger¸¦ »ç¿ëÇß´Ù. CrinTrigger »ç¿ëÇÔÀ¸·Î½á "¸ÅÁÖ ÆòÀÏ ¿ÀÈÄ 7½Ã" ¶Ç´Â "Åä¿äÀÏ°ú ÀÏ¿äÀÏ ¸Å 5ºÐ¸¶´Ù"¿Í °°Àº ½ºÄÉÁ층 ÀÛ¾÷À» ÇÒ ¼ö ÀÖ´Ù. ´õ ÀÌ»ó cron¿¡ °üÇØ ¼³¸íÇÏÁö´Â ¾ÊÀ» °ÍÀÌ´Ù. cron¿¡ °üÇÑ ¼¼ºÎ»çÇ×Àº CronTriggerÀÇ JavadocÀ» ÂüÁ¶Çϱ⠹ٶõ´Ù.

À§ÀÇ ¿¹Á¦¸¦ ½ÇÇàÇϱâ À§ÇØ Å¬·¡½ºÆо²¿¡ ±âº»ÀûÀÎ QuartzÀÇ ¼³Á¤À» ÇÏ´Â quartz.properties ÆÄÀÏÀ» ÇÊ¿ä·Î ÇÑ´Ù. ¸¸¾à ÆÄÀÏÀ̸§À» ´Ù¸£°Ô »ç¿ëÇϱ⸦ ¿øÇÑ´Ù¸é, ÆÄÀÏÀ̸§À» StdScheduleFactory »ý¼ºÀÚ¿¡ ÀÎÀÚ·Î Àü´ÞÇؾ߸¸ ÇÑ´Ù. ¾Æ·¡¿¡ ÃÖ¼ÒÇÑÀÇ ÇÁ·ÎÆÛƼµé¸¸ ¼³Á¤ÇÑ ÆÄÀÏÀÇ ¿¹Á¦°¡ ÀÖ´Ù:

#
# Configure Main Scheduler Properties 
#

org.quartz.scheduler.instanceName = TestScheduler
org.quartz.scheduler.instanceId = one

#
# Configure ThreadPool 
#

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount =  5
org.quartz.threadPool.threadPriority = 4

#
# Configure JobStore 
#

org.quartz.jobStore.misfireThreshold = 5000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Ç¥ÁØ Timer API¿¡ ºñÇØ Quartz°¡ °¡Áø ¶Ç ´Ù¸¥ ÀåÁ¡Àº ¾²·¹µå Ç®ÀÇ »ç¿ëÀÌ´Ù. Quartz´Â ÀÛ¾÷ ½ÇÇàÀ» À§ÇÑ ¾²·¹µå¸¦ ¾ò±â À§ÇØ ¾²·¹µå Ç®À» »ç¿ëÇÑ´Ù. ¾²·¹µå Ç®ÀÇ Å©±â´Â µ¿½Ã¿¡ ½ÇÇàµÉ ¼ö ÀÖ´Â ÀÛ¾÷ÀÇ ¼ö¿¡ ¿µÇâÀ» ¹ÌÄ£´Ù. ½ÇÇàÇؾßÇÒ ÀÛ¾÷ÀÌ ÀÖÁö¸¸ ¾²·¹µå Ç®¿¡ ³²¾Æ ÀÖ´Â ¾²·¹µå°¡ ¾ø´Ù¸é, ÀÛ¾÷Àº ¿©ºÐÀÇ ¾²·¹µå°¡ »ý±æ ¶§±îÁö sleep »óÅ°¡ µÉ °ÍÀÌ´Ù. ½Ã½ºÅÛ¿¡¼­ ¾ó¸¶³ª ¸¹Àº ¾²·¹µå¸¦ »ç¿ëÇÒ Áö´Â ¸Å¿ì °áÁ¤Çϱ⠾î·Á¿î ¹®Á¦ÀÌ°í, ½ÇÇèÀûÀ¸·Î °áÁ¤ÇÏ´Â °ÍÀÌ °¡Àå ÁÁ´Ù. ¾²·¹µå Ç® Å©±âÀÇ ±âº» °ªÀº 5ÀÌ°í ¼öõ°³ÀÇ ÀÛ¾÷À» ´Ù·çÁö ¾Ê´Â´Ù¸é ÀÌ°ÍÀº ÃæºÐÇÒ °ÍÀÌ´Ù. Quartz ÀÚü¿¡¼­ ±¸ÇöÇÑ ¾²·¹µå Ç®ÀÌ ÀÖÁö¸¸, ´Ù¸¥ ¾²·¹µå Ç®ÀÇ ±¸ÇöÀÌ ÀÖ´Ù¸é ±×°ÍÀ» »ç¿ëÇϴµ¥ Á¦¾àÀ» ¹ÞÁö´Â ¾Ê´Â´Ù.

ÀÌÁ¦ JobStore¿¡ °üÇØ »ìÆì º¸ÀÚ.JobStore´Â Job°ú Trigger¿¡ °üÇÑ ¸ðµç µ¥ÀÌÅ͸¦ º¸Á¸ÇÑ´Ù. µû¶ó¼­ ÀÛ¾÷¿¡ ¿µ¼Ó¼ºÀ» ºÎ¿©ÇÒ °ÍÀÎÁö ¾Æ´ÑÁö °áÁ¤ÇÏ´Â °ÍÀº ¾î¶² JobStore¸¦ »ç¿ëÇÏ´À³Ä¿¡ ´Þ·Á ÀÖ´Ù. ¿¹Á¦¿¡¼­ ¿ì¸®´Â org.quartz.simpl.RAMJobStore¸¦ »ç¿ëÇß´Ù. ÀÌ°ÍÀº ¸ðµç µ¥ÀÌÅÍ´Â ¸Þ¸ð¸®¿¡ ÀúÀåµÉ °ÍÀÌ°í ±×·¯¹Ç·Î ºñ ¿µ¼Ó¼ºÀ̶ó´Â °ÍÀ» ÀǹÌÇÑ´Ù. µû¶ó¼­ ¾ÖÇø®ÄÉÀ̼ÇÀÌ ´Ù¿îµÇ¸é ½ºÄÉÁ층 ÀÛ¾÷¿¡ °üÇÑ ¸ðµç µ¥ÀÌÅÍ´Â »ç¶óÁú °ÍÀÌ´Ù. ¾î¶² »óȲ¿¡¼­ ÀÌ°ÍÀº ¹Ù¶÷Á÷ÇÑ ¹æ½ÄÀÌ´Ù. ±×·¯³ª µ¥ÀÌÅ͸¦ º¸Á¸ÇÏ°í ½Í´Ù¸é ¾ÖÇø®ÄÉÀ̼ÇÀÌ org.quartz.simpl.JDBCJobStoreTX(¶Ç´Â org.quartz.simpl.JDBCJobStoreCMP)¸¦ »ç¿ëÇϵµ·Ï ¼³Á¤ÇØ¾ß ÇÑ´Ù.JDBCJobStoreTX´Â Á» ´õ ¸¹Àº ¼³Á¤ ÆĶó¹ÌÅ͸¦ ÇÊ¿ä·Î ÇÏ°í ±×°ÍÀº ¾Æ·¡ ¿¹Á¦¿¡¼­ ¼³¸íÇÒ °ÍÀÌ´Ù.

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = QRTZ_

#
# Configure Datasources 
#

org.quartz.dataSource.myDS.driver = org.postgresql.Driver
org.quartz.dataSource.myDS.URL = jdbc:postgresql:dev
org.quartz.dataSource.myDS.user = dejanb
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections  5
Quartz¿Í °ü°èÇü µ¥ÀÌÅͺ£À̽º¸¦ ¼º°øÀûÀ¸·Î »ç¿ëÇϱâ À§ÇÏ¿© ¸ÕÀú Quartz°¡ ÇÊ¿ä·Î ÇÏ´Â Å×À̺íÀ» »ý¼ºÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ÀûÀýÇÑ JDBC µå¶óÀ̹ö¸¦ °¡Áö°í ÀÖ´Ù¸é ¾î¶² µ¥ÀÌÅͺ£À̽º ¼­¹öµµ »ç¿ë °¡´ÉÇÏ´Ù. docs/dbTables Æú´õ¿¡¼­ ÇÊ¿äÇÑ Å×À̺íÀ» »ý¼ºÇÏ´Â ÃʱâÈ­ ½ºÅ©¸³Æ®¸¦ ãÀ» ¼ö ÀÖ´Ù.

Å×À̺íÀ» »ý¼ºÇÑ ÈÄ¿¡ Ç¥ÁØ SQL Äõ¸®¸¦ ƯÁ¤ RDBMSÀÇ SQL ¹®¹ý¿¡ ¸Â°Ô º¯°æÇØÁÖ´Â À§ÀÓ(delegate) Ŭ·¡½º¸¦ ¼±¾ðÇØ¾ß ÇÑ´Ù. ¿¹Á¦¿¡¼­ ¿ì¸®´Â PostgreSQLÀ» µ¥ÀÌÅͺ£À̽º ¼­¹ö·Î ¼±ÅÃÇß°í µû¶ó¼­ org.quartz.impl.jdbcjobstore.PostgreSQLDelegate Ŭ·¡½º¸¦ À§ÀÓ Å¬·¡½º·Î ¼³Á¤Çß´Ù. ´ç½ÅÀÌ »ç¿ëÇϴ ƯÁ¤ µ¥ÀÌÅͺ£À̽º ¼­¹ö¸¦ À§ÇØ ¾î¶² À§ÀÓ Å¬·¡½º¸¦ »ç¿ëÇØ¾ß ÇÏ´ÂÁö¿¡ °üÇÑ Á¤º¸´Â Quartz ¹®¼­¸¦ ÂüÁ¶Çϱ⠹ٶõ´Ù.

tablePrefix ÆĶó¹ÌÅÍ´Â µ¥ÀÌÅͺ£À̽º¿¡¼­ Quartz Å×À̺íÀÌ »ç¿ëÇÒ Á¢µÎ¾î¸¦ Á¤ÀÇÇÑ´Ù. µðÆúÆ®´Â QRTZ_ ÀÌ´Ù. ÀÌ·± ¹æ½ÄÀ¸·Î µ¥ÀÌÅͺ£À̽ºÀÇ ³ª¸ÓÁö Å×À̺í°ú ±¸ºÐÇÒ ¼ö ÀÖ´Ù.

»ç¿ëÇÏ´Â ¸Å JDBC store¸¶´Ù ¾î¶² datasource¸¦ »ç¿ëÇÒ °ÍÀÎÁö Á¤ÀÇÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ÀÌ°ÍÀº ÀϹÝÀûÀÎ JDBCÀÇ ¼³Á¤À̱⠶§¹®¿¡ ¿©±â¼­ ´õ ÀÌ»ó ¼³¸íÇÏÁö´Â ¾ÊÀ» °ÍÀÌ´Ù.

QuartzÀÇ ¶Ù¾î³­ Á¡Àº ÀÌ·¯ÇÑ ¼³Á¤À» º¯°æÇÑ ÈÄ¿¡ º¸°í¼­ »ý¼º ¿¹Á¦ÀÇ Äڵ带 ´Ü ÇÑÁÙµµ º¯°æÇÏÁö ¾Ê°í, µ¥ÀÌÅ͸¦ µ¥ÀÌÅͺ£À̽º¿¡ ÀúÀåÇÒ °ÍÀ̶ó´Â °ÍÀÌ´Ù.


Advanced Quartz
Áö±Ý±îÁö ÇÁ·ÎÁ§Æ®¿¡ Quartz¸¦ »ç¿ëÇϱâ À§ÇÑ ÁÁÀº ±âÃÊ°¡ µÉ ¼ö ÀÖ´Â ±âº»ÀûÀÎ °Í¿¡ ´ëÇØ »ìÆì º¸¾Ò´Ù. ÀÌ¿Ü¿¡µµ Quartz ¶óÀ̺귯¸®´Â ´ç½ÅÀÇ ¼ö°í¸¦ Å©°Ô ´ú¾îÁÙ ¼ö ÀÖ´Â ¶Ù¾î³­ ¾ÆÅ°ÅØÃĸ¦ °¡Áö°í ÀÖ´Ù.

Quartz´Â ±âº»ÀûÀ¸·Î Á¦°øÇÏ´Â °Í ¿Ü¿¡ ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¹®Á¦¸¦ ÇØ°áÇϴµ¥ µµ¿òÀÌ µÇ´Â ¶Ù¾î³­ ¾ÆÅ°ÅØÃĸ¦ °¡Áö°í ÀÖ´Ù. ±× Áß Áß¿äÇÑ ±â´É ÁßÀÇ Çϳª´Â listener ÀÌ´Ù: ÀÌ°ÍÀº ½Ã½ºÅÛ¿¡ ¾î¶² À̺¥Æ®°¡ ¹ß»ýÇÒ ¶§ È£ÃâµÈ´Ù. ¼¼ °¡Áö Á¾·ùÀÇ ¸®½º³Ê°¡ ÀÖ´Ù: JobListener, TriggerListener, SchedulerListener ÀÌ´Ù. 

¸®½º³Ê´Â ½Ã½ºÅÛ¿¡ ¹«¾ð°¡ ÀÌ»óÀÌ »ý°Ü¼­ ÀÌ¿¡ ´ëÇÑ °øÁö³ª ¾Ë¸² ±â´ÉÀ» ¿øÇÒ ¶§ ƯÈ÷ À¯¿ëÇÏ´Ù. ¿¹¸¦ µé¾î º¸°í¼­ »ý¼º Áß¿¡ ¿¡·¯°¡ ¹ß»ýÇÏ¸é °³¹ß ÆÀ¿¡°Ô À̸¦ ¾Ë¸®´Â ¿ì¾ÆÇÑ ¹æ¹ýÀº E-mailÀ̳ª SMS¸¦ º¸³»´Â JobListener ¸¦ ¸¸µå´Â °ÍÀÌ´Ù.

JobListener ´Â ´õ Èï¹Ì·Î¿î ±â´ÉÀ» Á¦°øÇÑ´Ù. ½Ã½ºÅÛ ÀÚ¿øÀÇ °¡¿ë¼º¿¡ Å©°Ô ÀÇÁ¸ÇÏ´Â ÀÏ(±×´ÙÁö ¾ÈÁ¤ÀûÀÌÁö ¸øÇÑ ³×Æ®¿öÅ©¿Í °°Àº)À» ´Ù·ç´Â ÀÛ¾÷À» »ó»óÇغ¸¶ó. ÀÌ·¯ÇÑ °æ¿ì ÀÛ¾÷ÀÌ ½ÇÇàµÉ ¶§ ÀÚ¿øÀÌ »ç¿ë ºÒ°¡´ÉÇÏ´Ù¸é À̸¦ Àç½ÇÇà ½ÃÅ°´Â ¸®½º³Ê¸¦ ¸¸µé ¼ö ÀÖ´Ù.

Quartz´Â ¶ÇÇÑ Trigger °¡ À߸ø ½ÇÇàµÇ°Å³ª ½ºÄÉÁì·¯°¡ ´Ù¿îµÇ¼­ ½ÇÇàµÇÁö ¾Ê¾ÒÀ» ¶§ÀÇ »óȲÀ» ´Ù·ê ¼ö ÀÖ´Ù. Trigger Ŭ·¡½ºÀÇ setMisfireInstruction() ¸Þ¼Òµå¸¦ »ç¿ëÇÔÀ¸·Î½á ¿À½ÇÇà¿¡ °üÇÑ Ã³¸®¸¦ ¼³Á¤ÇÒ ¼ö ÀÖ´Ù. ÀÌ ¸Þ¼Òµå´Â ¿À½ÇÇà ¸í·É ŸÀÔÀ» ÀÎÀÚ·Î ¹Þ¾ÆµéÀΰí, ±× °ªÀº ´ÙÀ½ÁßÀÇ Çϳª°¡ µÉ ¼ö ÀÖ´Ù:

Trigger.INSTRUCTION_NOOP: ¾Æ¹« Àϵµ ÇÏÁö ¾Ê´Â´Ù. 
Trigger.INSTRUCTION_RE_EXECUTE_JOB: Áï½Ã ÀÛ¾÷À» ½ÇÇàÇÑ´Ù. 
Trigger.INSTRUCTION_DELETE_TRIGGER: ¿À½ÇÇàÇÑ ÀÛ¾÷À» »èÁ¦ÇÑ´Ù. 
Trigger.INSTRUCTION_SET_TRIGGER_COMPLETE: ÀÛ¾÷ÀÌ ¿Ï·á¸¦ ¼±¾ðÇÑ´Ù. 
Trigger.INSTRUCTION_SET_ALL_JOB_TRIGGERS_COMPLETE: ÀÛ¾÷À» À§ÇÑ ¸ðµç triggerÀÇ ¿Ï·á¸¦ ¼±¾ðÇÑ´Ù. 
Trigger.MISFIRE_INSTRUCTION_SMART_POLICY: ƯÁ¤ TriggerÀÇ ±¸Çö¿¡ °¡Àå ¾Ë¸ÂÀº ¿À½ÇÇà ó¸® ¸í·ÉÀ» ¼±ÅÃÇÑ´Ù. 
CronTrigger¿Í °°Àº Trigger ±¸ÇöÀº À¯¿ëÇÑ ¿À½ÇÇà ó¸® ¸í·ÉÀ» »õ·Î Á¤ÀÇÇÒ ¼ö ÀÖ´Ù. ÀÌ°Í¿¡ °üÇÑ ´õ ¸¹Àº Á¤º¸´Â ÀÌ Å¬·¡½ºµéÀÇ JavadocÀ» Âü°íÇϱ⠹ٶõ´Ù. TriggerListener¸¦ »ç¿ëÇÔÀ¸·Î½á ¿À½ÇÇàÀÌ ¹ß»ýÇßÀ» °æ¿ì ÃëÇÒ ¾×¼Ç¿¡ °üÇØ ´õ ¸¹Àº Á¦¾î±ÇÀ» °¡Áú ¼ö ÀÖ´Ù. ¶ÇÇÑ Æ®¸®°ÅÀÇ ½ÇÇàÀ̳ª Á¾·á¿Í °°Àº Æ®¸®°Å À̺¥Æ®¿¡ ¹ÝÀÀÇϱâ À§ÇØ ÀÌ°ÍÀ» »ç¿ëÇÒ ¼ö ÀÖ´Ù.

SchedulerListener ´Â ½ºÄÉÁì·¯ Á¾·á³ª ÀÛ¾÷°ú Æ®¸®°ÅÀÇ Ãß°¡³ª Á¦°Å¿Í °°Àº ÀüüÀûÀÎ ½Ã½ºÅÛ À̺¥Æ®¸¦ ´Ù·é´Ù.

¿©±â¼­ ¿ì¸®´Â º¸°í¼­ »ý¼º ¿¹Á¦¸¦ À§ÇÑ °£´ÜÇÑ JobListener ¸¦ º¸¿©ÁÙ °ÍÀÌ´Ù. ¸ÕÀú JobListener ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇϴ Ŭ·¡½º¸¦ ÀÛ¼ºÇØ¾ß ÇÑ´Ù.

package net.nighttale.scheduling;

import org.quartz.*;


public class MyJobFailedListener implements JobListener {

  public String getName() {
    return "FAILED JOB";
  }

  public void jobToBeExecuted
    (JobExecutionContext arg0) {
  }


  public void jobWasExecuted(
    JobExecutionContext context,
    JobExecutionException exception) {

    if (exception != null) {
      System.out.println(
        "Report generation error"
      );
      // TODO notify development team
    }        
  }
}
±×¸®°í ¿¹Á¦ÀÇ main ¸Þ¼Òµå¿¡ ´ÙÀ½À» Ãß°¡ÇÑ´Ù:

sched.addGlobalJobListener(new MyJobFailedListener());
ÀÌ ¸®½º³Ê¸¦ ½ºÄÉÁì·¯ ÀÛ¾÷ ¸®½º³ÊÀÇ Àüü ¸ñ·Ï¿¡ Ãß°¡ÇÔÀ¸·Î½á ¸®½º³Ê´Â ¸ðµç ÀÛ¾÷ÀÇ À̺¥Æ®¿¡ ´ëÇØ È£Ãâ µÉ °ÍÀÌ´Ù. ¹°·Ð ¸®½º³Ê¸¦ ƯÁ¤ ÀÛ¾÷¿¡ ´ëÇؼ­¸¸ ¼³Á¤ÇÒ ¼öµµ ÀÖ´Ù. ±×·¸°Ô Çϱâ À§ÇØ SchedulerÀÇ addJobListeners() ¸Þ¼Òµå¸¦ »ç¿ëÇØ¾ß ÇÑ´Ù. ±×¸®°í JobDetailÀÇ addJobListener() ¸Þ¼Òµå¸¦ »ç¿ëÇؼ­ µî·ÏµÈ ¸®½º³Ê¸¦ ¸®½º³ÊÀÇ ÀÛ¾÷ ¸ñ·Ï¿¡ Ãß°¡Çضó. ÀÌ ¶§ ¸®½º³Ê À̸§À» ÆĶó¹ÌÅÍ·Î »ç¿ëÇÑ´Ù. ¸®½º³Ê À̸§Àº ¸®½º³ÊÀÇ getName() ¸Þ¼ÒµåÀÇ ¸®ÅÏ°ªÀ» ¸»ÇÑ´Ù.

sched.addJobListener(new MyJobFailedListener());
jobDetail.addJobListener("FAILED JOB");
¸®½º³Ê°¡ Á¤¸»·Î µ¿ÀÛÇÏ´ÂÁö Å×½ºÆ®Çϱâ À§ÇØ, ´ÙÀ½À» º¸°í¼­ »ý¼º ÀÛ¾÷ÀÇ execute() ¸Þ¼Òµå ¾È¿¡ Ãß°¡ÇÑ´Ù. 

throw new JobExecutionException();
ÀÛ¾÷ÀÌ ½ÇÇàµÈ ÈÄ ¸®½º³ÊÀÇ jobWasExecuted() ¸Þ¼Òµå°¡ ½ÇÇàµÇ°í, ¿¹¿Ü°¡ ¹ß»ýÇÑ´Ù. ¿¹¿Ü´Â null ÀÌ ¾Æ´Ï±â ¶§¹®¿¡ "Report generation error" ¸Þ¼¼Áö¸¦ È­¸é¿¡¼­ º¼ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

¸®½º³Ê¿¡ °üÇÑ ¸¶Áö¸· »çÇ×Àº ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¼º´ÉÀ» ¶³¾î¶ß¸± ¼ö Àֱ⠶§¹®¿¡ ½Ã½ºÅÛ¿¡¼­ »ç¿ëµÇ´Â ¸®½º³ÊÀÇ °¹¼ö¿¡ À¯ÀÇÇؾßÇÑ´Ù´Â °ÍÀÌ´Ù. 

QuartzÀÇ ±â´ÉÀ» È®ÀåÇÒ ¼ö ÀÖ´Â ¹æ¹ýÀÌ ÇÑ °¡Áö ´õ ÀÖ´Ù. ±×°ÍÀº Ç÷¯±× ÀÎÀ» ÀÌ¿ëÇÏ´Â °ÍÀÌ´Ù. Ç÷¯±× ÀÎÀº ½ÇÁúÀûÀ¸·Î ¿©·¯ºÐÀÌ ÇÊ¿äÇÑ ¾î¶² Àϵµ ÇÒ ¼ö ÀÖ´Ù; ´ÜÁö ÇؾßÇÒ ÀÏÀº org.quartz.spi.SchedulerPlugin ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇÏ´Â °Í »ÓÀÌ´Ù. ÀÌ ÀÎÅÍÆäÀ̽º´Â ±¸ÇöÇؾßÇÒ µÎ °³ÀÇ ¸Þ¼Òµå¸¦ Á¤ÀÇÇÑ´Ù -- Çϳª´Â ÃʱâÈ­(½ºÄÉÁì·¯ °´Ã¼¸¦ ÆĶó¹ÌÅÍ·Î ¹Þ´Â)¸¦ À§ÇÑ °ÍÀÌ°í, ¶Ç Çϳª´Â Á¾·á¸¦ À§ÇÑ °ÍÀÌ´Ù. ³ª¸ÓÁö´Â ¸ðµÎ ¿©·¯ºÐ¿¡°Ô ´Þ·Á ÀÖ´Ù. SchedulerFactory °¡ Ç÷¯±× ÀÎÀ» »ç¿ëÇϵµ·Ï Çϱâ À§ÇØ quartz.properties ÆÄÀÏ¿¡ Ç÷¯±× ÀΠŬ·¡½º¿Í ¸î °¡Áö ¿É¼Ç ¼³Á¤ ÆĶó¹ÌÅÍ(Ç÷¯±×Àθ¦¿¡¼­ ÇÊ¿ä·Î ÇÏ´Â)¸¦ Ãß°¡ÇÑ´Ù. In order to make SchedulerFactory use a certain plug-in, all you have to do is to add a line in the properties file (quartz.properties) with the plug-in class and a few optional configuration parameters (which depend on the particular plug-in). There are a few plug-ins already in Quartz itself. One is the shutdownHook, which can be used to cleanly shut down the scheduler in case the JVM terminates. To use this plug-in, just add the following lines in the configuration file:

org.quartz.plugin.shutdownHook.class = 
   org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownHook.cleanShutdown = true

¾î¶² ȯ°æ¿¡¼­µµ À¶Å뼺 ÀÖ´Â
Áö±Ý±îÁö Standalone ¾ÖÇø®ÄÉÀ̼ǿ¡¼­ Quartz¸¦ »ç¿ëÇÏ´Â °ÍÀ» »ìÆì ºÃ´Ù. ÀÌÁ¦ Quartz ÀÎÅÍÆäÀ̽º¸¦ ÀÚ¹Ù °³¹ßÀÚÀÇ °¡Àå º¸ÆíÀûÀΠȯ°æ ÇÏ¿¡¼­ ¾î¶»°Ô »ç¿ëÇÏ´ÂÁö »ìÆì º¸ÀÚ.

RMI
RMI¸¦ »ç¿ëÇÏ´Â ºÐ»ê ¾ÖÇø®ÄÉÀ̼ǿ¡¼­ Quartz´Â Áö±Ý±îÁö º» °Í°ú ¸¶Âù°¡Áö·Î °£´ÜÇÏ´Ù. Â÷ÀÌÁ¡Àº ¼³Á¤ ÆÄÀÏ ¹Û¿¡ ¾ø´Ù.

µÎ °¡Áö Çʼö ´Ü°è°¡ ÀÖ´Ù: ¸ÕÀú Quratz¸¦ ¿ì¸®ÀÇ request¸¦ ´Ù·ç´Â RMI ¼­¹ö·Î ¼³Á¤ÇÏ´Â °ÍÀÌ´Ù. ±×·¯°í ³ª¸é ´ÜÁö ÀϹÝÀûÀÎ ¹æ½ÄÀ¸·Î »ç¿ëÇϱ⸸ ÇÏ¸é µÈ´Ù.

ÀÌ ¿¹Á¦ÀÇ ¼Ò½º ÄÚµå´Â ½ÇÁúÀûÀ¸·Î ù¹ø° ¿¹Á¦¿Í µ¿ÀÏÇÏÁö¸¸, ¿ì¸®´Â ÀÌ°ÍÀ» µÎ ºÎºÐÀ¸·Î ³ª´­ °ÍÀÌ´Ù: ½ºÄÉÁì·¯ ÃʱâÈ­¿Í ½ºÄÉÁì·¯ »ç¿ë.

package net.nighttale.scheduling.rmi;

import org.quartz.*;

public class QuartzServer {

  public static void main(String[] args) {
        
    if(System.getSecurityManager() != null) {
      System.setSecurityManager(
        new java.rmi.RMISecurityManager()
      );
    }
           
    try {
      SchedulerFactory schedFact =
       new org.quartz.impl.StdSchedulerFactory();
      Scheduler sched = schedFact.getScheduler();
      sched.start();        
    } catch (SchedulerException se) {
      se.printStackTrace();
    }
  }
}
À§¿¡¼­ º¼ ¼ö ÀÖµíÀÌ, ½ºÄÉÁì·¯ ÃʱâÈ­ ÄÚµå´Â security manager¸¦ ¼³Á¤ÇÏ´Â ºÎºÐÀ» Æ÷ÇÔÇÏ°í ÀÖ´Ù´Â °Í ¿Ü¿£ ´Ù¸¥ °Í°ú ´Ù¸¦ ¹Ù ¾ø´Ù. Áß¿äÇÑ °ÍÀº ¼³Á¤ ÆÄÀÏ(quartzServer.properties)¾È¿¡ ÀÖ´Ù. ±×°ÍÀº ´ÙÀ½°ú °°´Ù:

#
# Configure Main Scheduler Properties 
#
org.quartz.scheduler.instanceName = Sched1
org.quartz.scheduler.rmi.export = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099
org.quartz.scheduler.rmi.createRegistry = true

#
# Configure ThreadPool 
#

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4

#
# Configure JobStore 
#

org.quartz.jobStore.misfireThreshold = 5000

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
°­Á¶µÈ ºÎºÐÀ» ÁÖ¸ñÇ϶ó. ÀÌ°ÍÀº ÀÌ ½ºÄÉÁì·¯°¡ RMI¸¦ ÅëÇÏ¿© ÀÎÅÍÆäÀ̽º¸¦ ¹ÝÃâÇÏ°í RMI registry¸¦ ½ÇÇàÇϱâ À§ÇØ ÆĶó¹ÌÅ͵éÀ» Á¦°øÇØ¾ß ÇÑ´Ù´Â °ÍÀ» º¸¿©ÁØ´Ù.

¼­¹ö¸¦ ¼º°øÀûÀ¸·Î ¹èÄ¡Çϱâ À§ÇØ ¸î °¡Áö ÇÒ ÀÏÀÌ ´õ ÀÖ´Ù. ±×°ÍµéÀº ¸ðµÎ RMI¸¦ ÅëÇÏ¿© °´Ã¼¸¦ ¹ÝÃâÇϱâ À§ÇÑ ÀüÇüÀûÀÎ ÀÛ¾÷ÀÌ´Ù. ¸ÕÀú rmiregistry ¸¦ ½ÃÀÛÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ÀÌ°ÍÀº ´ÙÀ½°ú °°ÀÌ È£ÃâÇÔÀ¸·Î½á ÀÌ·ç¾îÁø´Ù: À¯´Ð½º ½Ã½ºÅÛ¿¡¼­´Â

   rmiregistry &
¶Ç´Â À©µµ¿ì Ç÷§Æû¿¡¼­´Â

   start rmiregistry


´ÙÀ½¿¡ QuartzServer Ŭ·¡½º¸¦ ´ÙÀ½°ú °°Àº ¿É¼ÇÀ¸·Î ½ÃÀÛÇÑ´Ù:

java  -Djava.rmi.server.codebase
   file:/home/dejanb/quartz/lib/quartz.jar
   -Djava.security.policyrmi.policy
   -Dorg.quartz.propertiesquartzServer.properties
   net.nighttale.scheduling.rmi.QuartzServer
ÀÌÁ¦ ÀÌ·¯ÇÑ ÆĶó¹ÌÅ͵éÀ» Á» ´õ ÀÚ¼¼ÇÏ°Ô »ìÆ캸ÀÚ. QuartzÀÇ Ant ºôµå ŽºÅ©´Â ÇÊ¿äÇÑ RMI Ŭ·¡½º¸¦ Ŭ¶óÀ̾ðÆ®°¡ codebase·Î °¡¸®Å°µµ·Ï ÀÌ Å¬·¡½ºµéÀ» »ý¼ºÇÏ´Â rmic È£ÃâÀ» Æ÷ÇÔÇÏ°í ÀÖ´Ù. ±×·¯±â À§ÇØ ºôµå ÆÄÀÏ¿¡ -Djava.rmi.server.codebase ÆĶó¹ÌÅÍ·Î ½ÃÀÛÇϵµ·Ï ¼³Á¤ÇØ¾ß ÇÑ´Ù:Ãß°¡ÀûÀ¸·Î quartz.jar ÀÇ ¿ÏÀüÇÑ °æ·Îµµ Æ÷ÇԵǾî¾ß ÇÑ´Ù.(¹°·Ð ÀÌ°ÍÀº ¶óÀ̺귯¸®ÀÇ URLÀÌ µÉ ¼öµµ ÀÖ´Ù.)

ºÐ»ê ½Ã½ºÅÛ¿¡¼­ Áß¿äÇÑ À̽´´Â º¸¾ÈÀÌ´Ù; ±×·¯¹Ç·Î RMI´Â º¸¾È Á¤Ã¥À» »ç¿ëÇϵµ·Ï °­Á¦ÇÒ °ÍÀÌ´Ù. ¿¹Á¦¿¡¼­´Â ¸ðµç ±ÇÇÑÀ» Çã¿ëÇÏ´Â ±âº» Á¤Ã¥(rmi.policy)À» »ç¿ëÇß´Ù.

grant {
  permission java.security.AllPermission;
};
½ÇÁ¦ Àû¿ëÇÒ ¶§´Â ½Ã½ºÅÛÀÇ º¸¾È ¿ä±¸»çÇ׿¡ µû¶ó Á¤Ã¥À» º¯°æÇØ¾ß ÇÑ´Ù.

ÀÌÁ¦ ½ºÄÉÁì·¯´Â RMI¸¦ ÅëÇØ JobÀ» ¹Þ¾ÆµéÀÏ Áغñ°¡ µÇ¾ú´Ù. ÀÌÁ¦ Ŭ¶óÀ̾ðÆ® Äڵ带 »ìÆ캸ÀÚ.

package net.nighttale.scheduling.rmi;

import org.quartz.*;
import net.nighttale.scheduling.*;

public class QuartzClient {

  public static void main(String[] args) {
    try {
      SchedulerFactory schedFact =
       new org.quartz.impl.StdSchedulerFactory();
      Scheduler sched = schedFact.getScheduler();
      JobDetail jobDetail = new JobDetail(
        "Income Report",
        "Report Generation",
        QuartzReport.class
      );
                
      CronTrigger trigger = new CronTrigger(
        "Income Report",
        "Report Generation"
      );
      trigger.setCronExpression(
        "0 0 12 ? * SUN"
      );
      sched.scheduleJob(jobDetail, trigger);
    } catch (Exception e) {
      e.printStackTrace();
    }
   }
}
À§¿¡ ³ª¿Â ¹Ù¿Í °°ÀÌ Å¬¶óÀ̾ðÆ® ¼Ò½º´Â ÀÌÀü ¿¹Á¦¿Í µ¿ÀÏÇÏ´Ù. ¹°·Ð ¿©±â¿¡µµ quartzClient.properties ÀÇ ¼³Á¤Àº ´Ù¸£´Ù. Ãß°¡ÇØ¾ß ÇÒ °ÍÀº ÀÌ ½ºÄÉÁì·¯°¡ RMI Ŭ¶óÀ̾ðÆ®(proxy)ÀÌ°í, ¼­¹ö¸¦ ãÀ» registryÀÇ À§Ä¡¸¦ ¼³Á¤ÇÏ´Â °Í »ÓÀÌ´Ù.

# Configure Main Scheduler Properties  

org.quartz.scheduler.instanceName = Sched1
org.quartz.scheduler.rmi.proxy = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1099
³ª¸ÓÁö´Â ¸ðµÎ ¼­¹ö Ãø¿¡¼­ ÀÌ·ç¾îÁö±â ¶§¹®¿¡ Ŭ¶óÀ̾ðÆ® Ãø¿¡ ÀÌ¿ÜÀÇ ´Ù¸¥ ¾î¶² ¼³Á¤µµ ÇÊ¿äÇÏÁö ¾Ê´Ù. »ç½Ç ´Ù¸¥ ¼³Á¤ÀÌ ÀÖ´ÙÇصµ ÀÌ°ÍÀº ¹«½ÃµÉ °ÍÀÌ´Ù. Áß¿äÇÑ °ÍÀº ½ºÄÉÁì·¯ÀÇ À̸§Àº Ŭ¶óÀ̾ðÆ®¿Í ¼­¹öÀÇ ¼³Á¤ÀÌ ÀÏÄ¡ÇØ¾ß ÇÑ´Ù´Â °ÍÀÌ´Ù.(¿¹Á¦ÀÇ °æ¿ì Shed1) ±×·¯¸é ½ÃÀÛÇϱâ À§ÇÑ Áغñ´Â ³¡³µ´Ù. ´ÜÁö ¸®´ÙÀÌ·ºÆ®µÈ ÇÁ·ÎÆÛƼ ÆÄÀϷΠŬ¶óÀ̾ðÆ®¸¦ ½ÃÀÛÇϱ⸸ ÇÏ¸é µÈ´Ù:

java -Dorg.quartz.properties
       quartzClient.properties
       net.nighttale.scheduling.rmi.QuartzClient
ÀÌÁ¦ ¼­¹ö Äֿܼ¡¼­ ù¹ø° ¿¹Á¦¿Í °°Àº °á°ú¸¦ º¼ ¼ö ÀÖÀ» °ÍÀÌ´Ù.

À¥°ú ¿£ÅÍÇÁ¶óÀÌÁî ȯ°æ
À¥À̳ª ¿£ÅÍÇÁ¶óÀÌÁî ȯ°æÀÇ ¼Ö·ù¼ÇÀ» °³¹ßÇÏ°í ÀÖ´Ù¸é, ½ºÄÉÁì·¯¸¦ ½ÃÀÛÇϱâ À§ÇÑ ÀûÀýÇÑ °÷Àº ¾îµðÀÎÁö Àǹ®ÀÌ »ý±æ °ÍÀÌ´Ù. ÀÌ°ÍÀ» À§ÇØ Quartz´Â org.quartz.ee.servlet.QuartzInitializerServlet¸¦ Á¦°øÇÑ´Ù. ÇÒ ÀÏÀº ´ÜÁö web.xml ÆÄÀÏ¿¡ ´ÙÀ½ ¼³Á¤À» Ãß°¡ÇÏ´Â °Í »ÓÀÌ´Ù:


  
   QuartzInitializer
  
  
   Quartz Initializer Servlet
  
  
   org.quartz.ee.servlet.QuartzInitializerServlet
  
  
   1
  

JobÀ» EJB ¸Þ¼Òµå¿¡¼­ È£ÃâÇÏ°í ½Í´Ù¸é, org.quartz.ee.ejb.EJBInvokerJob Ŭ·¡½º¸¦ JobDetail ¿¡ Àü´ÞÇØ¾ß ÇÑ´Ù. ÀÌ·¯ÇÑ ±â¹ýÀ» º¸¿©ÁÖ±â À§ÇØ, ReportGenerator¸¦ ¼¼¼ÇºóÀ¸·Î ±¸ÇöÇÏ°í ¼­ºí¸´À¸·ÎºÎÅÍ generateReport() ¸Þ¼Òµå¸¦ È£ÃâÇÒ °ÍÀÌ´Ù.

package net.nighttale.scheduling.ee;

import java.io.IOException;

import javax.servlet.*;
import net.nighttale.scheduling.Listener;
import org.quartz.*;
import org.quartz.ee.ejb.EJBInvokerJob;
import org.quartz.impl.StdSchedulerFactory;

public class ReportServlet implements Servlet {

  public void init(ServletConfig conf)
    throws ServletException {
    JobDetail jobDetail = new JobDetail(
      "Income Report",
      "Report Generation",
      EJBInvokerJob.class
    );
    jobDetail.getJobDataMap().put(
      "ejb",
      "java:comp/env/ejb/Report"
    );
    jobDetail.getJobDataMap().put(
      "method",
      "generateReport"
    );
    Object[] args = new Object[0];
    jobDetail.getJobDataMap().put("args", args);
    CronTrigger trigger = new CronTrigger(
      "Income Report",
      "Report Generation"
    );
    try {
      trigger.setCronExpression(
        "0 0 12 ? * SUN"
      );
      Scheduler sched =
       StdSchedulerFactory.getDefaultScheduler();
      sched.addGlobalJobListener(new Listener());
      sched.scheduleJob(jobDetail, trigger);
      System.out.println(
        trigger.getNextFireTime()
      );
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public ServletConfig getServletConfig() {
    return null;
  }

  public void service(ServletRequest request,
                      ServletResponse response)
    throws ServletException, IOException {
  }

  public String getServletInfo() {
    return null;
  }

  public void destroy() {
  }
}
À§¿¡ ³ª¿Â ¹Ù¿Í °°ÀÌ, job¿¡ Àü´ÞÇÒ ÇÊ¿ä°¡ ÀÖ´Â ÆĶó¹ÌÅÍ°¡ 3°³°¡ ÀÖ´Ù.

ejb: ¿£ÅÍÇÁ¶óÀÌÁî ºóÀÇ JNDI À̸§. 
method: ½ÇÁ¦ È£ÃâµÇ¾ß ÇÒ ¸Þ¼ÒµåÀÇ À̸§. 
args: ¸Þ¼ÒµåÀÇ ÀÎÀÚ·Î Àü´ÞµÇ¾ß ÇÒ °´Ã¼ÀÇ ¹è¿­. 
³ª¸ÓÁö´Â QuartzÀÇ ÀÏ¹Ý »ç¿ë¹ý°ú ´Ù¸¥ °ÍÀÌ ¾ø´Ù. °£´ÜÇÏ°Ô Çϱâ À§ÇØ ÀÌ ¿¹Á¦¸¦ ¼­ºí¸´ÀÇ ÃʱâÈ­ ¸Þ¼Òµå¿¡ À§Ä¡½ÃÄ×Áö¸¸, ¹°·Ð ¾ÖÇø®ÄÉÀ̼ÇÀÇ ¾î¶°ÇÑ À§Ä¡¿¡ ³õ¾Æµµ »ó°ü ¾ø´Ù. Quartz¸¦ ¼º°øÀûÀ¸·Î ½ÇÇàÇϱâ À§ÇØ À¥ ¾ÖÇø®ÄÉÀ̼ǿ¡ ÀÌ EJB¸¦ µî·ÏÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ÀϹÝÀûÀ¸·Î web.xml ÆÄÀÏ¿¡ ´ÙÀ½À» Ãß°¡ÇÏ¸é µÈ´Ù.


  ejb/Report
  Session
  net.nighttale.scheduling.ee.ReportHome
  net.nighttale.scheduling.ee.Report
  ReportEJB

¾î¶² ¾ÖÇø®ÄÉÀÌ¼Ç ¼­¹ö(Orion°ú °°Àº)´Â À¯Àú ¾²·¹µå¸¦ »ý¼ºÇϱâ À§ÇÑ ±ÇÇÑÀ» ¼³Á¤ÇØ¾ß ÇÒ ÇÊ¿ä°¡ ÀÖ´Ù. ±×·¯¹Ç·Î -userThread¿Í °°Àº ¿É¼ÇÀ¸·Î ½ÇÇàÇØ¾ß ÇÒ °ÍÀÌ´Ù.

Áö±Ý±îÁö »ìÆì º» °ÍÀÌ QuartzÀÇ ¿£ÅÍÇÁ¶óÀÌÁî ±â´ÉÀÇ ÀüºÎ´Â ¾Æ´Ï´Ù. ±×·¯³ª óÀ½ ½ÃÀÛÇÒ ¶§ Âü°íÇÒ ¸¸ÇÒ °ÍÀÌ´Ù. Áö¼¼ÇÑ Á¤º¸¸¦ ¿øÇÑ´Ù¸é Quartz's Javadocs ¸¦ Âü°íÇϱ⠹ٶõ´Ù.

Web Services
Quartz´Â ÇöÀç À¥ ¼­ºñ½º¸¦ À§ÇØ ³»ÀåµÈ Áö¿øÀº ¾øÁö¸¸, XML-RPC À» ÅëÇÏ¿© ½ºÄÉÁì·¯ ÀÎÅÍÆäÀ̽º¸¦ ¹ÝÃâÇÏ´Â Ç÷¯±× ÀÎÀ» ãÀ» ¼ö ÀÖ´Ù. ¼³Ä¡ ÀýÂ÷´Â °£´ÜÇÏ´Ù. ½ÃÀÛÇϱâ À§ÇØ Ç÷¯±× ÀÎ ¼Ò½º¸¦ Quartz ¼Ò½º Æú´õ¿¡ ¾ÐÃàÀ» Ç®°í ´Ù½Ã ºôµåÇؾ߸¸ ÇÑ´Ù. Ç÷¯±× ÀÎÀº Jakarta XML-RPC ¶óÀ̺귯¸®¿¡ ÀÇÁ¸ÇϹǷÎ, ±×°ÍÀÌ Å¬·¡½ºÆо²¿¡ ÀâÇô ÀÖ´ÂÁö È®ÀÎÇØ¾ß ÇÑ´Ù. ´ÙÀ½¿¡ ÇÁ·ÎÆÛƼ ÆÄÀÏ¿¡ ¾Æ·¡ÀÇ ³»¿ëÀ» Ãß°¡ÇÑ´Ù.

org.quartz.plugin.xmlrpc.class = org.quartz.plugins.xmlrpc.XmlRpcPlugin
org.quartz.plugin.xmlrpc.port = 8080
ÀÌÁ¦ ½ºÄÉÁì·¯´Â XML-RPC¸¦ ÅëÇØ »ç¿ëÇÒ ¼ö ÀÖ´Â Áغñ°¡ µÇ¾ú´Ù. ÀÌ·¯ÇÑ ¹æ½ÄÀ¸·Î PHP³ª Perl°°Àº ´Ù¸¥ ¾ð¾î, ¶Ç´Â RMI°¡ ÀûÇÕÇÑ ÇØ°áÃ¥ÀÌ ¾Æ´Ñ ºÐ»ê ȯ°æ¿¡¼­, QuartzÀÇ ±â´É ÁßÀÇ ÀϺθ¦ »ç¿ëÇÒ ¼ö ÀÖ´Ù.

¿ä¾à
Áö±Ý±îÁö ÀÚ¹Ù¿¡¼­ ½ºÄÉÁ층À» ±¸ÇöÇÏ´Â µÎ °¡Áö ¹æ¹ý¿¡ ´ëÇØ »ìÆì ºÃ´Ù. Quartz´Â ¸Å¿ì °­·ÂÇÑ ¶óÀ̺귯¸®Áö¸¸, °£´ÜÇÑ ¿ä±¸»çÇ׿¡ ´ëÇؼ­´Â Timer API°¡ ½Ã°£À» Àý¾àÇÏ°í ½Ã½ºÅÛ¿¡ ºÒÇÊ¿äÇÑ º¹À⼺À» ÇÇÇÒ ¼ö ÀÖ°Ô ÇØ ÁØ´Ù. ½ºÄÉÁ층ÀÌ ÇÊ¿äÇÑ ÀÛ¾÷ÀÌ ±×´ÙÁö ¸¹Áö ¾Ê°í, ÇÁ·Î¼¼½º¿¡¼­ ½ÇÇà½Ã°£ÀÌ Àß ¾Ë·ÁÁ® ÀÖÀ» °æ¿ì(±×¸®°í ºÒº¯ÀÏ °æ¿ì) Timer API¸¦ »ç¿ëÇÒ °ÍÀ» °í·ÁÇضó. ÀÌ·¯ÇÑ »óȲ¿¡¼­ ½Ã½ºÅÛ ÁßÁö³ª ´Ù¿î ¶§¹®¿¡ ½ºÄÉÁ층 ÀÛ¾÷µéÀ» ÀÒ¾î¹ö¸± °Í¿¡ ´ëÇØ °ÆÁ¤ÇÒ ÇÊ¿ä´Â ¾ø´Ù. ´õ¿í º¹ÀâÇÑ ¿ä±¸»çÇ×À» À§Çؼ­´Â Quartz°¡ ¿ì¾ÆÇÑ ÇØ°áÃ¥ÀÌ´Ù. ¹°·Ð ¾ðÁ¦µçÁö Timer API¸¦ ±â¹ÝÀ¸·Î ´ç½Å ÀÚ½ÅÀÇ ÇÁ·¹ÀÓ¿öÅ©¸¦ ¸¸µé ¼ö ÀÖ´Ù. ±×·¯³ª ÀÌ¹Ì ´ç½ÅÀÌ ÇÊ¿ä·Î ÇÏ´Â ¸ðµç ±â´É(±×¸®°í ±× ÀÌ»óÀÇ ±â´É)À» Á¦°øÇÏ´Â ÈǸ¢ÇÑ ÇØ°áÃ¥ÀÌ Á¸ÀçÇϴµ¥ ¿Ö ±×·± ±ÍÂúÀ» ÀÏÀ» ÇÏ·Á´Â°¡?

ÇÑ °¡Áö ÁÖ¸ñÇÒ ¸¸ÇÑ À̺¥Æ®´Â IBM°ú BEAÀÌ Á¦ÃâÇÑ "Timer for Application Servers" JSR 236 ÀÌ´Ù. ÀÌ ½ºÆåÀº ½ºÄÉÁ층¿¡ °ü·ÃµÈ Ç¥ÁØ API°¡ ºÎÁ·ÇÑ J2EE ȯ°æ¿¡¼­ ŸÀ̸Ӹ¦ À§ÇÑ API¸¦ ¸¸µå´Â µ¥ ÃÐÁ¡À» µÎ°í ÀÖ´Ù. IBM's developerWorks site¿¡¼­ ½ºÆå¿¡ °ü·ÃµÈ º¸´Ù ÀÚ¼¼ÇÑ »çÇ×À» ãÀ» ¼ö ÀÖ´Ù. ÀÌ ½ºÆåÀº º½¿¡ ÀÏ¹Ý »ç¿ëÀÚ¿¡°Ô °ø°³µÉ °ÍÀÌ´Ù.

Dejan BosanacÀº DNS À¯·´ÀÇ ¼ÒÇÁÆ®¿þ¾î °³¹ßÀÚ ÀÌ´Ù.