본문으로 바로가기

웹 서버 개발이던 Rest 서버 개발이던 거의 모든 실제 현업 개발 환경에서 꼭 등장하는 것이 "배치"와 "스케쥴러" 이다. 사용자의 요청에 의해서 기능이 수행되는 것이 실제 업무 로직의 많은 부분을 차지하겠지만, 분명 시스템의 특정 부분은 "자동으로" 기능이 수행 되어야 하는 것이 존재한다.

순수하게 DB to DB로 작업하는 기능의 경우에는 오라클 등의 DBMS 자체에서 제공하는 스케쥴러 기능이 있지만, 많은 경우 서버단에서 스케쥴러를 개발해야 할 것이다. 이 또한 매우 다양한 방법이 있고, 몇몇 자주 사용되는 라이브러리가 존재한다. 그 중 내가 주로 자바 스케쥴러 개발에 사용하는 오픈소스 라이브러리인 Quartz Scheduler에 대해 작성해 보려고 한다.


개발 환경은 Maven 기반의 Spring boot 환경이지만, 기본 설정을 제외하고는 Gradle이나 기본 Spring3 등에서도 사용하는 방법은 비슷하다.



1. pom.xml에 Dependency 설정


당연한 말이겠지만 maven 환경에서 외부 라이브러리를 사용하기 위해서는 pom.xml에 디펜던시를 추가 해 주어야 한다. quartz 2.2.1을 아래처럼 추가해 주자.


1
2
3
4
5
6
7
8
9
10
11
12
<!-- Quartz scheduler -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>
 
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.1</version>
</dependency>
cs

이제 Quartz 라이브러리를 사용할 수 있게 되었을 것이다.



2. Job 코드 작성


Quartz Scheduler는 기능을 수행하는 단위인 Job과 스케쥴에 대한 정보를 가진 Trigger를 스케쥴러에 걸어 실행하는 구조이다. 먼저 스케쥴에 따라 동작할 Job클래스를 작성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
public class LcmgrTestJob implements Job {
 
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        /*
         * Job Interface를 implements하여
         * execute 메소드에 로직을 넣는다.
         * */
        System.out.println("--------------------------job수행---------------------------");
        System.out.println(DateUtil.getCurrentTimestamp());
    }
 
}
cs


quartz.Job 인터페이스를 implements하여 구현하게 된다.

해당 인터페이스의 execute 메소드를 상속받아 수행될 로직을 작성하면 된다. 스케쥴에 따라 job이 동작하는지 테스트하기 위해 sysout으로 메시지를 출력하고 현재 일시를 출력하는 간단한 코드를 작성했다.



3. 스케쥴러 코드 작성


이제 스케쥴에 따라 위에서 작성한 Job을 수행하는 코드를 Quartz 라이브러리를 사용해 개발할 차례이다. 우선 아래 코드를 보자.


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
@Component
public class LcmgrTestScheduler {
    private SchedulerFactory schedulerFactory;
    private Scheduler scheduler;
    
    @PostConstruct
    public void start() throws SchedulerException{
    
        schedulerFactory = new StdSchedulerFactory();
        scheduler = schedulerFactory.getScheduler();
        scheduler.start();
        
        //job 지정
        JobDetail job = JobBuilder.newJob(LcmgrTestJob.class).withIdentity("testJob").build();
        
        //trigger 생성
        Trigger trigger = TriggerBuilder.newTrigger().
                withSchedule(CronScheduleBuilder.cronSchedule("15 * * * * ?")).build();
//        startAt과 endAt을 사용해 job 스케쥴의 시작, 종료 시간도 지정할 수 있다.
//        Trigger trigger = TriggerBuilder.newTrigger().startAt(startDateTime).endAt(EndDateTime)
//                .withSchedule(CronScheduleBuilder.cronSchedule("*/1 * * * *")).build();
 
        scheduler.scheduleJob(job, trigger);
        
    }
}
cs


Spring bean으로 등록하기 위해 클래스에 @Component 어노테이션을 달아 줬으며, 실제 스케쥴러를 구현한 start() 메소드에 @postConstruct 어노테이션을 달아 줬다. 

@postConstruct 어노테이션을 간략하게 설명하자면, 해당 클래스가 인스턴스화 되자마자 자동으로 동작하게 하려는 메소드에 선언해 주는 어노테이션이다. 즉, 위 클래스가 인스턴스화 되자 마자 start() 메소드가 동작 할 것이다.

스케쥴러를 통한 배치 잡 자체가 사용자의 동작 없이 자동으로 수행하게 하기 위한 로직이기 때문에 어딘가에서 메소드를 호출 해 실행하기 보다는 이런식으로 자동으로 로직이 수행되도록 구현하는 것이 좋다.


quartz.SchedulerFactory를 선언한 후, quartz.Scheduler를 .getScheduler() 메소드를 통해 지정해준다. 

그 뒤, 해당 스케쥴러를 .start() 해 주는 것으로 스케쥴러를 시작 하겠다는 명령을 내리게 된다.


14번 라인에서 이제 아까 작성한 job을 지정해 줄 차례이다. 

identity는 해당 job을 구분하는 고유 명을 지정해 주면 된다. 간혹 같은 job 로직이라도 서로 다른 스케쥴로 동작하게 할 경우가 있기 때문에 각각의 job은 고유한 identity를 가져야 한다.


17번 라인에서 trigger를 코딩해준다. trigger는 TriggerBuiler 클래스를 사용해 구현하게 되는데, 스케쥴러를 수행할 스케쥴 정보를 담고 있다. 

이 때, Cron 문법을 사용해 스케쥴을 지정하는 방법이 주로 사용된다. 주석 친 부분처럼 startAt이나 endAt을 사용해 스케쥴을 시작할 시작, 종료 일시를 지정해 줄 수 도 있다.

위 코드에서 넣어준 cron인 "15 * * * * ?" 는 매 분 15초에 동작하라는 의미이다. 크론 문법에 대해서는 추후 별도 포스팅 하겠다.


마지막으로 스케쥴러에 job과 trigger를 연결해 주면 끝난다. 물론 job과 trigger를 여러 개 만들어 각각 scheduler에 지정해 주면 여러 개의 job 스케쥴이 동시에 작동하게 된다.



3. 스케쥴러 실행


스케쥴러를 호출해 실행하는 방법 역시 개발자가 구현하기 나름이겠지만, 배치 스케쥴에 대한 시작, 종료 정보와 동작주기 등을 이미 스케쥴러 클래스에서 다 지정해 주기 때문에 보통 서버 시작과 동시에 호출해서 사용하게 된다.

나는 Spring boot를 사용하였기 때문에 아래 코드처럼 main 메소드가 있는 application 클래스에서 개발한 스케쥴러를 Autowired하여 서버 시작과 동시에 자동으로 동작하게 구현했다.


1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class LcmgrApplication {
    
    @Autowired
    private LcmgrTestScheduler scheduler;
 
    public static void main(String[] args) {
        SpringApplication.run(LcmgrApplication.class, args);
    }
}
cs


서버를 구동시켜 보면 설정한 대로 매 분 15초마다 해당 job이 동작하여 로그를 찍어 주는 것을 확인 할 수 있다.



 Other Contents 

댓글을 달아 주세요

  1. 나그네 2017.11.26 00:02

    Job에서 @Autowired가 되나요?