본문 바로가기
Back-end/JAVA

[JAVA] Quartz 스케줄러 만들기 (1) - 실행

by 허도치 2020. 11. 9.
서론

  예전에 커뮤니티 사이트에서 글목록을 수집하고 DB에 저장하는 크롤러를 만든적이 있었다. 이 때, 주기적으로 실행하기 위해서 crontab이나 Windows 작업 스케줄러를 사용했다. 이 두개의 스케줄러는 사용하기는 편하지만 프로그램과 스케줄을 별도로 관리해야하기 때문에 관리포인트가 늘어나는 단점이 있다. 

  그래서, 이번에는 스케줄러를 직접 만들어보려고 하는데 Spring Batch는 써본적이 있기 때문에 이번에는 Quartz로 만들어 보려고 한다.

 

 

 

개발환경

    - jdk-11.0.5

    - quartz-2.3.2

<dependency>
	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz</artifactId>
	<version>2.3.2</version>
</dependency>

 

 

 

Quartz란?

    - Java Scheduling 라이브러리.
    - 일련의 작업들을 단발성, 주기성으로 실행할 수 있음.

 

 

구성요소
1. JOB

    - 실제 작업을 수행하는 객체 

    - org.quartz.Job 인터페이스를 상속받아 execute 메소드에 수행 로직을 구현

    - 같은 그룹에는 동일한 이름을 가진 Job을 생성할 수 없음

 

2. Trigger

    - Job을 수행하기위한 조건(스케줄)을 정의한 객체
    - 특정시간, 횟수, 반복주기 등을 설정할 수 있음

       * 특정시간 및 횟수: SimpleTrigger

       * 주기적으로 반복: CronTrigger

    - 같은 그룹에는 동일한 이름을 가진 Job을 생성할 수 없음
    - Job : Trigger = 1 : N
      

3. Listener

    - 작업의 시작, 중간, 끝, 에러를 처리할 수 있는 객체

    - ScheduleListener와 TriggerListener

 

 

 

소스코드
1. SampleJobExecutor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
 
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
 
import sch.listeners.MyScheduleListener;
import sch.listeners.MyTriggerListener;
 
/**
 * Quartz Job
 */
public class SampleJobExecutor implements Job {
    
    private static final SimpleDateFormat TIMESTAMP_FMT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSSS"); 
    
    @Override
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
        JobDataMap jobDataMap = ctx.getJobDetail().getJobDataMap();
        
        String currentDate = TIMESTAMP_FMT.format(new Date());
        String triggerKey = ctx.getTrigger().getKey().toString();
        String message = jobDataMap.getString("message");
        
        System.out.println(String.format("[%s][%s] %s", currentDate, triggerKey, message ));
    }
}
 
/**
 * Quartz Scheduler 실행
 */
class JobLuacher {
    public static void main(String[] args) {
        try {
            
            // Scheduler 생성
            SchedulerFactory factory = new StdSchedulerFactory();
            Scheduler scheduler = factory.getScheduler();
            
            scheduler.getListenerManager().addJobListener(new MyScheduleListener());
            scheduler.getListenerManager().addTriggerListener(new MyTriggerListener());
            
            // Scheduler 실행
            scheduler.start();
            
            // JOB Data 객체 생성
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("message""Hello, Quartz!!!");
            
            // JOB Executor Class
            Class<extends Job> jobClass = SampleJobExecutor.class;
 
            // JOB 생성
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                                    .withIdentity("job_name""job_group")
                                    .setJobData(jobDataMap)
                                    .build();
            
            // SimpleTrigger 생성
            // 4초마다 반복하며, 최대 5회 실행
            SimpleScheduleBuilder simpleSch = SimpleScheduleBuilder.repeatSecondlyForTotalCount(54);
            SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                                            .withIdentity("simple_trigger""simple_trigger_group")
                                            .withSchedule(simpleSch)
                                            .forJob(jobDetail)
                                            .build();
 
            // CronTrigger 생성
            // 15초주기로 반복( 0, 15, 30, 45 )
            CronScheduleBuilder cronSch = CronScheduleBuilder.cronSchedule(new CronExpression("0/15 * * * * ?"));
            CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger()
                                        .withIdentity("cron_trigger""cron_trigger_group")
                                        .withSchedule(cronSch)
                                        .forJob(jobDetail)
                                        .build();
            
            // JobDtail : Trigger = 1 : N 설정
            Set<Trigger> triggerSet = new HashSet<Trigger>();
            triggerSet.add(simpleTrigger);
            triggerSet.add(cronTrigger);
 
            // Schedule 등록
            scheduler.scheduleJob(jobDetail, triggerSet, false);
            
        } catch (ParseException | SchedulerException e) {
            e.printStackTrace();
        }
    }
}
cs

 

 

 

실행결과

 

 

 

마치며

  이것으로 간단하게 Quartz로 스케줄러를 만들고 실행하는 방법에 대해서 알아보았다. 만들어보니 Spring Batch보다 훨씬 간단했다. 다만, 스케줄을 Annotation으로 등록할 수 있는 Spring Batch와는 다르게 Trigger 객체를 생성해야하는 번거로움이 있다. 그래도, Quartz가 좀 더 직관적이라 마음에 든다.

댓글