IT/WEB

[JAVA] 스케줄러(Quartz) 실행하는 법

오달달씨 2021. 10. 13. 09:00
728x90
반응형

스케줄러란? 

일정주기마다 특정 작업을 실행시키는 기능

 

일정한 시간, 일정한 주기마다 DB를 조회하거나 API 호출하는 등 작업을 실행해야 하는 경우가 있다. JAVA에서는 Quartz라는 lib을 이용해서 스케줄러를 구현할 수 있다. 메인메소드를 통해 일정한 주기로 작업을 실행하는 스케줄러를 만들어보겠다.

 

- SampleJobExecutor.java (Job 인터페이스 상속)

package com.odumak.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class SampleJobExecutor implements Job {

	private static final SimpleDateFormat TIMESTAMP_FMT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSSS"); 
	public static final String EXECUTION_COUNT = "EXECUTION_COUNT";
	
	@Override
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
        JobDataMap map = ctx.getJobDetail().getJobDataMap();
        String currentDate = TIMESTAMP_FMT.format(new Date());
        String message = map.getString("message");
 
        int executeCount = 0;
        if (map.containsKey(EXECUTION_COUNT)) {
            executeCount = map.getInt(EXECUTION_COUNT);
        }
        executeCount += 1;
        map.put(EXECUTION_COUNT, executeCount);
        
        System.out.println(String.format("[%-18s][%d][%s] %s", "execute", executeCount, currentDate, message ));
    }

}

- MyJobListner.java

package com.odumak.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;

public class MyJobListener implements JobListener {

	 @Override
	    public String getName() {
	        return MyJobListener.class.getName();
	    }
	 
	    /**
	     * Job이 수행되기 전 상태
	     *   - TriggerListener.vetoJobExecution == false
	     */
	    @Override
	    public void jobToBeExecuted(JobExecutionContext context) {
	        System.out.println(String.format("[%-18s][%s] 작업시작", "jobToBeExecuted", context.getJobDetail().getKey().toString()));
	    }
	 
	    /**
	     * Job이 중단된 상태
	     *   - TriggerListener.vetoJobExecution == true
	     */
	    @Override
	    public void jobExecutionVetoed(JobExecutionContext context) {
	        System.out.println(String.format("[%-18s][%s] 작업중단", "jobExecutionVetoed", context.getJobDetail().getKey().toString()));
	    }
	 
	    /**
	     * Job 수행이 완료된 상태
	     */
	    @Override
	    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
	        System.out.println(String.format("[%-18s][%s] 작업완료", "jobWasExecuted", context.getJobDetail().getKey().toString()));
	    }

}

 

- MyTriggerListner.java

package com.odumak.quartz;

import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;

public class MyTriggerListener implements TriggerListener {

public static final String EXECUTION_COUNT = "EXECUTION_COUNT";
    
    public String getName() {
        return MyTriggerListener.class.getName();
    }
    
    /**
     * Trigger가 실행된 상태
     * 리스너 중에서 가장 먼저 실행됨
     */
    public void triggerFired(Trigger trigger, JobExecutionContext context) {
        System.out.println(String.format("\n[%-18s][%s]", "triggerFired", trigger.getKey().toString()));
    }
 
    /**
     * Trigger 중단 여부를 확인하는 메소드
     * Job을 수행하기 전 상태
     * 
     * 반환값이 false인 경우, Job 수행
     * 반환값이 true인 경우, Job을 수행하지않고 'SchedulerListtener.jobExecutionVetoed'로 넘어감
     * 
     * Job 실행횟수가 3회이상이면 작업중단
     */
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
        JobDataMap map = context.getJobDetail().getJobDataMap();
        int executeCount = -1;
        if (map.containsKey(EXECUTION_COUNT)) {
            executeCount = map.getInt(EXECUTION_COUNT);
        }
        System.out.println(String.format("[%-18s][%s]", "vetoJobExecution", trigger.getKey().toString()));
        
        return executeCount >= 3;
    }
 
    /**
     * Trigger가 중단된 상태
     */
    public void triggerMisfired(Trigger trigger) {
        System.out.println(String.format("[%-18s][%s]", "triggerMisfired", trigger.getKey().toString()));
    }
 
    /**
     * Trigger가 완료된 상태
     */
    public void triggerComplete(Trigger trigger, JobExecutionContext context, CompletedExecutionInstruction triggerInstructionCode) {
        System.out.println(String.format("[%-18s][%s]", "triggerComplete", trigger.getKey().toString()));
    }

}

- JobLuacher.java

package com.odumak.quartz;

import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.ListenerManager;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

public class JobLuacher {
	public static void main(String[] args) {
		try {
            // Scheduler 생성
            SchedulerFactory factory = new StdSchedulerFactory();
            Scheduler scheduler = factory.getScheduler();
            
            // Listener 설정
            ListenerManager listenrManager = scheduler.getListenerManager(); 
            listenrManager.addJobListener(new MyJobListener());
            listenrManager.addTriggerListener(new MyTriggerListener());
            
            // Scheduler 실행
            scheduler.start();
 
            // JOB Executor Class
            Class<? extends Job> jobClass = SampleJobExecutor.class;
            
            // JOB Data 객체 생성
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("message", "Hello, Quartz!!!");
            jobDataMap.put(SampleJobExecutor.EXECUTION_COUNT, 0);
 
            // JOB 생성
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                                    .withIdentity("job_name", "job_group")
                                    .setJobData(jobDataMap)
                                    .build();
            
            // SimpleTrigger 생성
            // 5초마다 반복하며, 최대 10회 실행
            SimpleScheduleBuilder simpleSch = SimpleScheduleBuilder.simpleSchedule()
                                                .withRepeatCount(10)
                                                .withIntervalInSeconds(5);
            SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                                            .withIdentity("simple_trigger", "simple_trigger_group")
                                            .withSchedule(simpleSch)
                                            .forJob(jobDetail)
                                            .build();
 
            // Schedule 등록
            scheduler.scheduleJob(jobDetail, simpleTrigger);
 
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
	}
}

 

- 결과값

728x90
반응형