2015-01-25 2 views
8

애플리케이션에서, 스프링 애플 리케이션 (Spring Tomcat)을 Spring Boot (V1.2.1) 응용 프로그램으로 변환 한 이후로, 쿼츠 기반 예약 작업이 더 이상 작동하지 않습니다.스프링 부트 : Quartz 작업 실행에서 @Service 사용하기

나는 다음과 같이 이러한 석영 작업을 예약 :

// My own Schedule object which holds data about what to schedule when 
Schedule schedule = scheduleService.get(id of the schedule); 

String scheduleId = schedule.getId(); 

JobKey jobKey = new JobKey(scheduleId); 
TriggerKey triggerKey = new TriggerKey(scheduleId); 

JobDataMap jobData = new JobDataMap(); 
jobData.put("scheduleId", scheduleId); 

JobBuilder jobBuilder = JobBuilder.newJob(ScheduledActionRunner.class) 
    .withIdentity(jobKey) 
    .withDescription(schedule.getName()) 
    .usingJobData(jobData); 

JobDetail job = jobBuilder.build(); 

TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger() 
    .forJob(jobKey) 
    .withIdentity(triggerKey) 
    .withDescription(schedule.getName()); 

triggerBuilder = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.toCronExpression())); 

Trigger trigger = triggerBuilder.build(); 

org.quartz.Scheduler scheduler = schedulerFactoryBean.getScheduler(); 

scheduler.scheduleJob(job, trigger); 

ScheduledActionRunner :

@Component 
public class ScheduledActionRunner extends QuartzJobBean { 

    @Autowired 
    private ScheduleService scheduleService; 

    public ScheduledActionRunner() { 
    } 

    @Override 
    public void executeInternal(final JobExecutionContext context) throws JobExecutionException { 
     SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
     final JobDataMap jobDataMap = context.getMergedJobDataMap(); 
     final String scheduleId = jobDataMap.getString("scheduleId"); 
     final Schedule schedule = scheduleService.get(scheduleId); 
     // here it goes BANG since scheduleService is null 
    } 
} 

ScheduleService 최대 절전 모드에서 데이터를 가져 오는 고전적인 봄 서비스입니다. 위에서 말했듯이 스프링 부트로 이동할 때까지는 제대로 작동합니다.

클래식 코드로이 코드를 구현 한 경우 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);은 서비스 자동 응답을 처리하기 위해이 트릭을 사용했습니다.

스프링 부트 환경에서이 기능을 다시 사용하려면 무엇이 필요합니까?

편집 : 나는 봄의 ThreadPoolTaskScheduler.The 코드에 찬성 석영을 사용하여 멀리 이동하기로 결정했습니다 끝에

훨씬 단순화했고 예상대로 작동합니다.

+0

코멘트 public (!) 방법에 다음과 같은 주석을 배치 그 후

@EnableScheduling public class Application{ .... 

을 배치 간단하여 스케줄러를 사용하는 응용 프로그램을 구성 할 수 있습니다 Spring.Boot을 사용하여 Dewfy (주석을 달 수있는 담당자가 충분하지 않기 때문에) : 최대 절전 모드 세션이 연결되지 않았다는 오류가있어서 @Transactional 주석으로 메서드를 표시해야했습니다. – gooboo

답변

11

SpringBeanAutowiringSupport는 웹 응용 프로그램 컨텍스트를 사용하며, 귀하의 경우에는 사용할 수 없습니다. 석영에 스프링 관리 콩이 필요한 경우에는 봄에 제공되는 석영 지지대를 사용해야합니다. 이렇게하면 모든 관리 빈에 대한 전체 액세스 권한이 부여됩니다. 자세한 내용은 스프링 문서의 석영 섹션 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html을 참조하십시오. 또한 다음과 같은 스프링 관리 콩을 사용하는 석영 예제를 참조하십시오. 예제는 코드를 기반으로합니다. 따라서 스프링 대안을 사용하여 첫 번째 코드 단편 (쿼츠 초기화가 완료된 곳)을 변경할 수 있습니다.

만들기

@Component 
public class ActionCronTriggerFactoryBean extends CronTriggerFactoryBean { 

    @Autowired 
    private ScheduledActionRunnerJobDetailFactory jobDetailFactory; 

    @Value("${cron.pattern}") 
    private String pattern; 

    @Override 
    public void afterPropertiesSet() throws ParseException { 
     setCronExpression(pattern); 
     setJobDetail(jobDetailFactory.getObject()); 
     super.afterPropertiesSet(); 
    } 

} 

를 트리거 공장 작업 세부 공장

@Component 
public class ScheduledActionRunnerJobDetailFactory extends JobDetailFactoryBean { 

    @Autowired 
    private ScheduleService scheduleService; 

    @Override 
    public void afterPropertiesSet() { 
     setJobClass(ScheduledActionRunner.class); 
     Map<String, Object> data = new HashMap<String, Object>(); 
     data.put("scheduleService", scheduleService); 
     setJobDataAsMap(data); 
     super.afterPropertiesSet(); 
    } 
} 

만들기 그리고 마지막으로 당신이 질문에

@Component 
public class ActionSchedulerFactoryBean extends SchedulerFactoryBean { 

    @Autowired 
    private ScheduledActionRunnerJobDetailFactory jobDetailFactory; 

    @Autowired 
    private ActionCronTriggerFactoryBean triggerFactory; 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     setJobDetails(jobDetailFactory.getObject()); 
     setTriggers(triggerFactory.getObject()); 
     super.afterPropertiesSet(); 
    } 

} 
+0

@Babl에게 감사드립니다. 제안 된 코드를 시험해보기 전에 나의 유일한 질문은 "응용 프로그램이 스프링 부트를 사용하기 전에 변경된 이유는 무엇입니까?이전의 Spring Boot는 이미 JavaConfig와 Spring 4.1에 기반을두고 있었고 스케줄링은 잘 작동했습니다. – yglodt

+1

앞서 언급했듯이 SpringBeanAutowiringSupport는 빈을 찾고 객체에 삽입하기 위해 웹 응용 프로그램 컨텍스트를 사용하지만 스프링 부트 응용 프로그램이 완전히 웹 응용 프로그램이 아니기 때문에 컨텍스트가 null입니다. 따라서 디버그 레벨에서 SpringBeanAutowiringSupport에 대한 로그를 활성화하면 대상 클래스가 Spring 웹 애플리케이션에서 생성되지 않았다는 것을 알리는 devug 메시지가 표시됩니다. 봄에 디버그 레벨을 켜는 방법으로 문제에 대한 많은 내부 정보를 얻을 수 있습니다.) – Babl

+0

자세한 설명 주셔서 감사합니다! – yglodt

9

내 대답은하지 완전히 일치하는 SchedulerFactory을 만들 수 있지만 봄에 노출 어떤 능력이라도 cron-expression 기반 스케줄러를 시작할 수 있습니다.

단지에서 답변을 @Service

@Service 
public class MyService{ 
... 
    @Scheduled(cron = "0 * * * * MON-FRI") 
    public void myScheduledMethod(){ 
    .... 
    } 
+2

고마워, 나는 이것을 알고 있으며 정적 인 일정을 이미 사용하고있다. 위에서 설명한 문제는 사용자가 설정할 수있는 일정에서 비롯된 것이므로 런타임에 추가/편집/제거해야합니다. 이는 @Scheduled 주석으로는 가능하지 않습니다. – yglodt

관련 문제