본문 바로가기

JAVA Quartz 라이브러리를 이용해 스케줄러 배치 프로그램 개발

다프트코더 2023. 9. 22.
반응형

시스템에서 스케줄러를 이용한 배치 프로그램은 매우 중요한 역할을 한다. 보통 현장에서 데이터를 Summary하거나 시스템간 데이터를 통합 관리할 때 많이 사용한다.

과거에는 PL/SQL을 이용해 Batch Job을 만들거나 DB Link를 이용해 직접 타 시스템 데이터베이스에 접근하는 방법을 사용했는데 요즘에는 스케줄러 배치 프로그램을 만들어서 사용하는 추세다. 그래서 JAVA로 Quartz 라이브러리를 이용해 간단한 스케줄러 배치 프로그램을 만들어보았다.

반응형

👉 Quartz 란?

Java 애플리케이션 내에 통합될 수 있는 다양한 기능을 갖춘 오픈 소스 Job 스케줄링 라이브러리다.
여러 Job들을 실행하기 위한 일정을 만들 수 있다.

👉 Quartz 라이브러리 추가하기

Maven을 이용해 Quartz 라이브러리를 추가하자.
pom.xml 파일 <dependencies> 안에 아래 코드를 추가하자

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

👉 Quartz 구성요소

Job, JobListener, TriggerListener 를 상속하는 클래스들을 생성한다.

1. Job

실제 작업을 수행하는 역할을 한다.
Job 인터페이스를 상속받아 execute 메서드에 로직을 구현한다.

2. JobListener

Job의 시작, 중단, 완료시점을 처리할 수 있는 객체다.

3. TriggerListener

Trigger의 시작, 작업 실행 거부, 실패, 완료시점을 처리할 수 있는 객체다.

4. SchedulerListener

Job과 Trigger에 대한 세부 기능들을 처리할 수 있는 객체다.
(ex: Trigger 멈춤, Job 석제 및 추가 등등)
JobListener, TriggerListener 2개로도 충분히 기능을 구현할 수 있다.

👉 소스 코드

1. MyJobLauncher.java

main 함수를 갖고있는 클래스로 Quartz Scheduler를 실행한다.

public class MyJobLauncher {

	public static void main(String[] args) {

		try {
			SchedulerFactory factory = new StdSchedulerFactory();
			Scheduler scheduler = factory.getScheduler();

			// Listener 설정
			ListenerManager listenrManager = scheduler.getListenerManager();
			listenrManager.addJobListener(new MyJobListener());
			listenrManager.addTriggerListener(new MyTriggerListener());
			listenrManager.addSchedulerListener(new MyScheduleListener());

			// Job Executer 설정
			Class<? extends Job> jobClass = MyJob.class;

			// Job Data 셋업
			JobDataMap jobDataMap = new JobDataMap();
			jobDataMap.put("message", "Hello Quartz Scheduler!");

			// Job 생성
			JobDetail jobDetail = JobBuilder.newJob(jobClass).usingJobData(jobDataMap).build();

			// Cron Trigger 생성
			// 20초마다 반복(0, 20, 40)
			CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
					.cronSchedule(new CronExpression("0/20 * * * * ?"));
			CronTrigger cronTrigger = (CronTrigger) TriggerBuilder.newTrigger().withIdentity("cron", "cron_group")
					.withSchedule(cronScheduleBuilder).forJob(jobDetail).build();

			// Simple Trigger 생성
			// 10초마다 총 6회 반복
			SimpleScheduleBuilder simpleSch = SimpleScheduleBuilder.repeatSecondlyForTotalCount(6, 10);
			SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
					.withIdentity("simple", "simple_group").withSchedule(simpleSch).forJob(jobDetail).build();

			// Trigger 설정
			Set<Trigger> triggerSet = new HashSet<Trigger>();
			triggerSet.add(cronTrigger);
			triggerSet.add(simpleTrigger);

			// Schedule 등록
			scheduler.scheduleJob(jobDetail, triggerSet, false);
			scheduler.start();

		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}

2. MyJob.java

Job의 기능을 구현하는 클래스다. execute 메서드안에 Job 기능에 맞게 로직을 구현하면 된다.

public class MyJob implements Job {

	private SimpleDateFormat simpleDataformat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSSSSS");

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
		String currentDate = simpleDataformat.format(new Date());
		String triggerKey = context.getTrigger().getKey().toString();
		String message = jobDataMap.getString("message");
		System.out.println(String.format("[%s][%s] %s", currentDate, triggerKey, message));
	}
}

3. MyJobListener.java

JobListener 인터페이스를 상속받아 Job의 시작, 중단, 완료시점에 로직을 구현할 수 있다.

public class MyJobListener implements JobListener {

	@Override
	public String getName() {
		return MyJobListener.class.getName();
	}

	@Override
	public void jobToBeExecuted(JobExecutionContext context) {
		System.out.println(
				String.format("[%-26s][%s] 작업시작", "jobToBeExecuted", context.getJobDetail().getKey().toString()));
	}

	@Override
	public void jobExecutionVetoed(JobExecutionContext context) {
		System.out.println(
				String.format("[%-26s][%s] 작업중단", "jobExecutionVetoed", context.getJobDetail().getKey().toString()));
	}

	@Override
	public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
		System.out.println(
				String.format("[%-26s][%s] 작업완료", "jobWasExecuted", context.getJobDetail().getKey().toString()));
	}
}

4. MyTriggerListener.java

TriggerListener 인터페이스를 상속받아 Trigger의 시작, 작업 실행 거부, 실패, 완료시점에 로직을 구현할 수 있다.

public class MyTriggerListener implements TriggerListener {

	public static final String EXECUTION_COUNT = "EXECUTION_COUNT";

	public String getName() {
		return MyTriggerListener.class.getName();
	}

	@Override
	public void triggerFired(Trigger trigger, JobExecutionContext context) {
		System.out.println(String.format("[%-26s][%s] Trigger 발사", "triggerFired", trigger.getKey().toString()));
	}

	@Override
	public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
		// 여기가 True 일 경우 수행 안됨
		System.out.println(
				String.format("[%-26s][%s] Trigger 발사 거부 체크", "vetoJobExecution", trigger.getKey().toString()));
		return false;

	}

	@Override
	public void triggerMisfired(Trigger trigger) {
		System.out.println(String.format("[%-26s][%s] Trigger 불발", "triggerMisfired", trigger.getKey().toString()));

	}

	@Override
	public void triggerComplete(Trigger trigger, JobExecutionContext context,
			CompletedExecutionInstruction triggerInstructionCode) {
		System.out.println(String.format("[%-26s][%s] Trigger 완료", "triggerComplete", trigger.getKey().toString()));
        System.out.println("==============================================================================================");
	}
}

👉 실행 결과

1개의 Job이 두개의 Trigger를 통해 반복 수행하는 모습을 볼 수 있다.

Quartz 라이브러리를 이용해 간단한 스케줄러 배치 프로그램을 만들어봤다. 여기에 좀 더 응용을 하면 매우 강력한 프로그램이 될 수 있다. 웹 크롤러 프로그램부터 기업의 EAI 시스템 구축까지도 가능하다.

다음 포스팅에는 Quartz 라이브러리의 환경 설정과 좀 더 깊이 있는 기능들을 알아보겠다.

반응형

댓글