블로그 이미지
봉뎅구리

Rss feed Tistory
프로그래밍이야기/Framework 2011.10.31 11:33

Spring 3 quartz

스케쥴링이 필요하여 quartz를 이번에 처음 사용해보기로 하여 개발을 하던 도중 스케줄링 진입점이 되는 job class에서 autowired 어노테이션을 사용하여 service class의 메서드를 호출 하려 했으나... fail......... O<-<(으어)

알아본 결과 spring 과 quartz 간의 라이프 사이클이 서로 달라 발생하는 문제점이라더라.
해결 방법을 알아본 결과 QuartzJobBean을 상속하여 excuteInternal method를 오버라이딩 해서 spring의 sppicationContext에 등록된 bean을 사용 할 수 있도록 처리를 해야 했다.
(참고 : http://xenomity.tistory.com/95 )

JobSuper.java
package com.test.quartz

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;

public abstract class JobSuper extends QuartzJobBean {
    private ApplicationContext ctx;
 
    @Override
    protected void executeInternal(JobExecutionContext jobexecutioncontext) throws JobExecutionException {
        // TODO Auto-generated method stub
  
        ctx = (ApplicationContext)jobexecutioncontext.getJobDetail().getJobDataMap().get("applicationContext");
  
        executeJob(jobexecutioncontext);
    }
 
    protected Object getBean(String beanId) {
        return ctx.getBean(beanId);
    }
 
    protected abstract void executeJob(JobExecutionContext jobexecutioncontext);
}

TestJob.java
package com.test.quartz.job

import org.quartz.JobExecutionContext;

import com.test.quartz.JobSuper;
import com.test.service.TestService;

public class TestJob extends JobSuper {
    @Override
    protected void executeJob(JobExecutionContext jobexecutioncontext) {
        TestService testService = (TestService)super.getBean("testServiceImpl"); //get service bean from spring applicationContext
  
        testService.executeTestService(); //call service method
    }
}

TestService.java & TestServiceImpl.java
package com.test.service

public interface TestService {
    public void executeTestService();
}

=================================================================================================================================================================

pacakge com.test.service.impl

import java.util.Date;
import java.text.SimpleDateFormat;
import com.test.service.TestService

@Service
public class TestServiceImpl implements TestService {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    @Override
    public void executeTestService() {
        System.out.println("DO TestService::executeTestService!!![TIME : " + dateFormat.format(new Date()) + "]");
    }
}

applicationContext.xml
<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                                         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                         http://www.springframework.org/schema/context
                                         http://www.springframework.org/schema/context/spring-context-3.0.xsd"

    <context:annotation-config />
    <context:component-scan base-package="com.test" />

    <!-- Quartz ============================================================================================================================================= -->
    <bean id="testCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >
        <property name="jobDetail">
            <bean id="testJobProcess" class="org.springframework.scheduling.quartz.JobDetailBean">
                <property name="jobClass" value="com.test..quartz.job.TestJob" />
                <property name="applicationContextJobDataKey" value="applicationContext" />
            </bean>
        </property>
        <property name="cronExpression" value="0/5 * * * * ?" />
    </bean>

    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="testCronTrigger" />
            </list>
        </property>
    </bean>
    <!-- ============================================================================================================================================= Quartz -->
</beans>



그런데 이 삽질을 하고 난 뒤 알아보니 Spring 3 의 scheduling 네임스페이스 또는 task XML 네임스페이스를 통한 방식으로도 처리가 가능하다 더라.
(게다가 더 쉽다 Autowired 어노테이션도 잘 먹는다 .... O<-< 으어)
이 방식을 사용 할 경우 위의 방식에JobSuper.java 는 필요 없으며 quartz jar파일도 필요 없으며 이에 따라 스케쥴러 진입점이 될 bean이 QuartzJobBean 을 상속 받을 필요도 없다.

TestService.java 및 TestServiceImpl.java 파일은 위 예제와 동일

TestJob.java
package com.test.quartz.job

import org.springframework.beans.factory.annotation.Autowired;

import com.test.service.TestService;

public class TestJob {
    @Autowired
    private TestService testService;

    @Override
    protected void executeJob(JobExecutionContext jobexecutioncontext) {
        testService.executeTestService(); //call service method
    }
}

applicationContext.xml
<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:task="http://www.springframework.org/schema/task"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                                         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                         http://www.springframework.org/schema/context
                                         http://www.springframework.org/schema/context/spring-context-3.0.xsd
                                         http://www.springframework.org/schema/task
                                         http://www.springframework.org/schema/task/spring-task-3.0.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.test" />

    <!-- Quartz ============================================================================================================================================= -->
    <task:scheduler id="scheduler" pool-size="10"/> <!-- pool-size attribute optional -->
 
    <task:scheduled-tasks scheduler="scheduler"> <!-- scheduled job list -->
        <task:scheduled ref="testJob" method="executeJob" cron="0/1 * * * * ?"/> <!-- 주기 설정 속성 : fixed-rate, fixed-delay, cron -->
        <!-- add more job here -->
    </task:scheduled-tasks>
 
    <!-- job bean -->
    <bean id="testJob" class="com.test.quartz.job.TestJob" />
    <!-- ============================================================================================================================================= Quartz -->
</beans>


두가지 방법을 다 알고 있어도 나쁠건 없을듯 하다.
저작자 표시
신고
TOTAL 82,671 TODAY 2