2013-07-01 2 views
4

저는 Quartz에 대해 매우 익숙하며 이제 스프링 웹 애플리케이션에서 일부 작업을 스케줄해야합니다.데이터베이스에서 Quartz 트리거를 유지하는 정확한 방법

저는 스프링 + 쿼츠 통합에 대해 알고 있습니다. (스프링 v 3.1.1을 사용하고 있습니다.) 이것이 올바른 방법인지 궁금합니다.

특히 을 데이터베이스에 유지해야 응용 프로그램을 다시 시작할 때 다시 초기화 할 수 있습니다.

스프링 스케쥴링 래퍼가 제공하는 유틸리티가 있습니까? 따라야 할 "잘 알려진"접근 방식을 제안 해 주시겠습니까?

+0

웹 응용 프로그램? –

+0

예, 내 프로젝트가 웹 응용 프로그램입니다. – davioooh

+0

작업이 시작시 호출되도록 구성되었는지 확인하기 위해 속성을 읽었을 것입니다. 서버를 다시 시작하는 동안 컨텍스트가로드되므로이 속성을 읽고 작업을 시작합니다. –

답변

12

이 시나리오를 처리하는 한 가지 방법이 있습니다.

첫 번째 봄 구성에서는 SchedulerFactoryBean을 지정하고 Scheduler을 다른 빈에 삽입 할 수 있습니다.

<bean name="SchedulerFactory" 
    class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
    <property name="applicationContextSchedulerContextKey"> 
     <value>applicationContext</value> 
    </property> 
</bean> 

그런 다음 응용 프로그램에서 작업을 만들 때 데이터베이스에 작업의 세부 정보를 저장합니다. 이 서비스는 내 컨트롤러 중 하나 그리고 스케줄 작업에 의해 호출됩니다

@Component 
public class FollowJobService { 

    @Autowired 
    private FollowJobRepository followJobRepository; 

    @Autowired 
    Scheduler scheduler; 

    @Autowired 
    ListableBeanFactory beanFactory; 

    @Autowired 
    JobSchedulerLocator locator; 

    public FollowJob findByClient(Client client){ 
     return followJobRepository.findByClient(client); 
    } 

    public void saveAndSchedule(FollowJob job) { 
     job.setJobType(JobType.FOLLOW_JOB); 
     job.setCreatedDt(new Date()); 
     job.setIsEnabled(true); 
     job.setIsCompleted(false); 

     JobContext context = new JobContext(beanFactory, scheduler, locator, job); 
     job.setQuartzGroup(context.getQuartzGroup()); 
     job.setQuartzName(context.getQuartzName()); 

     followJobRepository.save(job); 

     JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, job)); 
    } 
} 

내가 빌드 할 JobContext 해당 작업에 대한 세부 사항을 포함하고 결국 스케줄링 작업을위한 유틸리티로 전달됩니다. 다음은 실제로 작업을 예약하는 유틸리티 메소드의 코드입니다. 내 서비스에서 나는 JobScheduler을 autowire하고 JobContext으로 전달합니다. 또한 저장소를 사용하여 데이터베이스에 작업을 저장합니다. 그래서이 모든 코드 후

/** 
* Schedules a DATA_MINING_JOB for the client. The job will attempt to enter 
* followers of the target into the database. 
*/ 
@Override 
public void schedule(JobContext context) { 
    Client client = context.getNetworkSociallyJob().getClient(); 
    this.logScheduleAttempt(context, client); 

    JobDetail jobDetails = JobBuilder.newJob(this.getJobClass()).withIdentity(context.getQuartzName(), context.getQuartzGroup()).build(); 
    jobDetails.getJobDataMap().put("job", context.getNetworkSociallyJob()); 
    jobDetails.getJobDataMap().put("repositories", context.getRepositories()); 

    Trigger trigger = TriggerBuilder.newTrigger().withIdentity(context.getQuartzName() + "-trigger", context.getQuartzGroup()) 
      .withSchedule(cronSchedule(this.getSchedule())).build(); 

    try { 
     context.getScheduler().scheduleJob(jobDetails, trigger);    
     this.logSuccess(context, client); 

    } catch (SchedulerException e) { 
     this.logFailure(context, client); 
     e.printStackTrace(); 
    } 
} 

내 작업은 데이터베이스에 저장하고 그는 석영 스케줄러를 사용하여 예약 된, 내가 두 가지 일이 일어날 실행합니다. 이제 응용 프로그램이 다시 시작되면 스케줄러로 작업을 다시 예약하려고합니다. 이를 위해 콘테이너가 재시작되거나 시작될 때마다 스프링에 의해 호출되는 ApplicationListener<ContextRefreshedEvent>을 구현하는 빈을 등록한다.

<bean id="jobInitializer" class="com.network.socially.web.jobs.JobInitializer"/> 

JobInitializer.class

public class JobInitializer implements ApplicationListener<ContextRefreshedEvent> { 

    Logger logger = LoggerFactory.getLogger(JobInitializer.class); 

    @Autowired 
    DataMiningJobRepository repository; 

    @Autowired 
    ApplicationJobRepository jobRepository; 

    @Autowired 
    Scheduler scheduler; 

    @Autowired 
    JobSchedulerLocator locator; 

    @Autowired 
    ListableBeanFactory beanFactory; 

    @Override 
    public void onApplicationEvent(ContextRefreshedEvent event) { 
     logger.info("Job Initilizer started."); 

     //TODO: Modify this call to only pull completed & enabled jobs 
     for (ApplicationJob applicationJob : jobRepository.findAll()) { 
      if (applicationJob.getIsEnabled() && (applicationJob.getIsCompleted() == null || !applicationJob.getIsCompleted())) { 
       JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, applicationJob)); 
      } 
     }  
    } 

} 

이 클래스는 스케줄러와 ApplicationJob 인터페이스를 구현하는 내 작업의 각 인스턴스를 잡고 저장소를 autowires. 이 데이터베이스 레코드의 정보를 사용하여 스케줄러 유틸리티를 사용하여 작업을 재구성 할 수 있습니다.

그래서 기본적으로 데이터베이스에 작업을 수동으로 저장하고 적절한 빈에 Scheduler의 인스턴스를 주입하여 수동으로 작업을 예약합니다. 다시 일정을 잡으려면 데이터베이스에 쿼리 한 다음 ApplicationListener을 사용하여 컨테이너를 다시 시작하고 시작하는 시간을 고려하여 일정을 예약합니다.

+0

대단히 고맙습니다. 비슷한 생각을했습니다. 귀하의 시나리오를 따라 스케줄링 서비스를 모델링하겠습니다. – davioooh

+0

@davioooh 답변에 잠시 시간이 걸려 죄송합니다. 잠시 바빴지만 잠시 전 귀하의 질문을 보았습니다. 새 질문에도 동일한 도전이있었습니다. 도움이 필요하시면 내 프로필에있는 블로그에 내 이메일이 있습니다. –

+0

대단히 감사합니다 :) – davioooh

5

Spring과 Quartz JDBC 작업 저장소 통합에 사용할 수있는 문서가 꽤 있다고 가정합니다. 예를 들면 :

+0

+1 감사합니다. 좋은 제안 – davioooh

관련 문제