±âŸ(framework)
2018.06.29 / 21:58
Job Scheduling in Java
aichatbot
Ãßõ ¼ö 228
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 À¯·´ÀÇ ¼ÒÇÁÆ®¿þ¾î °³¹ßÀÚ ÀÌ´Ù.
¹ø¿ª ÇãŸí
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 À¯·´ÀÇ ¼ÒÇÁÆ®¿þ¾î °³¹ßÀÚ ÀÌ´Ù.