通过编程触发Spring Quartz任务

3
我有一个使用Sprint Boot - Java 8的应用程序,其中包含一个quartz任务,我在启动时进行配置并设置了一个计划。该任务会按照计划自动运行,就像quartz任务一样。然而,现在我希望用户能够通过前端页面上的按钮手动触发这些任务,而不会影响该任务的正常调度。以下是所有相关文件。

application.yml

quartz:
    fooCron: 0 0 1 * * ?
    fooGroup: foo-quartz-group

QuartzConfig.java

@Configuration
@ConfigurationProperties(prefix = "quartz")
public class QuartzConfig {
    private String fooCron;
    private String fooGroup;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private DataSource dataSource;

    @Bean
    public SchedulerFactoryBean quartzScheduler() {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);

        Trigger[] triggers = {fooTrigger().getObject()};

        SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
        quartzScheduler.setJobFactory(jobFactory);
        quartzScheduler.setTransactionManager(transactionManager);
        quartzScheduler.setDataSource(dataSource);
        quartzScheduler.setOverwriteExistingJobs(true);
        quartzScheduler.setSchedulerName("foo-scheduler");
        quartzScheduler.setQuartzProperties(quartzProperties());
        quartzScheduler.setTriggers(triggers);

        return quartzScheduler;
    }

    @Bean
    public CronTriggerFactoryBean fooTrigger() {
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setJobDetail(fooJob().getObject());
        cronTriggerFactoryBean.setCronExpression(fooCron);
        cronTriggerFactoryBean.setGroup(fooGroup);
        return cronTriggerFactoryBean;
    }

    @Bean
    public JobDetailFactoryBean fooJob() {
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        jobDetailFactoryBean.setJobClass(FooJob.class);
        jobDetailFactoryBean.setGroup(fooGroup);
        jobDetailFactoryBean.setDurability(true);
        return jobDetailFactoryBean;
    }

    @Bean
    public Properties quartzProperties() {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz/quartz.properties"));
        Properties properties = null;
        try {
            propertiesFactoryBean.afterPropertiesSet();
            properties = propertiesFactoryBean.getObject();
        } catch (IOException e) {
        }

        return properties;
    }

    //setters
}

FooJob.java

@Service
public class FooJob implements Job {
    private final FooRepository fooRepo; //This is a repository class annotated with @Repository.

    public FooJob(FooRepository fooRepo) {
        this.fooRepo = fooRepo;
    }

    @Override
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        //do stuff
    }
}

现在这个程序按照预定时间表运行。根据yml文件中的cron配置,0 0 1 * * ?,该作业每天凌晨1点执行。很棒!但是现在我想手动执行它。因此,我构建了一个控制器来接收来自UI的手动触发请求。

QuartzController.java

@RestController
@RequestMapping("/quartz")
public class QuartzController {
    private SchedulerFactoryBean schedulerFactoryBean;
    private Scheduler scheduler;

    public DevopsController(final SchedulerFactoryBean quartzScheduler) {
        this.schedulerFactoryBean = quartzScheduler;
        scheduler = schedulerFactoryBean.getScheduler();
    }

    @PostMapping("/execute")
    public ResponseEntity executeJob() {
        HttpStatus status = OK;
        try {
            TriggerKey triggerKey = new TriggerKey("fooTrigger", "foo-quartz-group");
            Trigger trigger = scheduler.getTrigger(triggerKey);
            ScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).withRepeatCount(0);
            JobDetail jobDetail = scheduler.getJobDetail(trigger.getJobKey());
            Trigger newTrigger = TriggerBuilder.newTrigger()
                                               .forJob(jobDetail)
                                               .startNow()
                                               .withIdentity(triggerKey)
                                               .withSchedule(scheduleBuilder)
                                               .startAt(Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()))
                                               .build();
            //I have tried all 3 of the following lines
            scheduler.scheduleJob(jobDetail, new HashSet<>(Arrays.asList(trigger)), true);
            //scheduler.addJob(jobDetail, true);
            //scheduler.rescheduleJob(triggerKey, newTrigger);
        } catch (SchedulerException e) {
            status = BAD_REQUEST;
        }

        return new ResponseEntity<>(status);
    }
}

但是每次运行应用程序并调用控制器的 scheduleJob 方法时,我会在控制台中收到以下错误:

org.quartz.SchedulerException: Job instantiation failed
    at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:45)
    at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127)
    at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:375)
Caused by: java.lang.InstantiationException: com.test.jobs.FooJob
    at java.lang.Class.newInstance(Class.java:427)
    at org.springframework.scheduling.quartz.AdaptableJobFactory.createJobInstance(AdaptableJobFactory.java:58)
    at org.springframework.scheduling.quartz.SpringBeanJobFactory.createJobInstance(SpringBeanJobFactory.java:74)
    at com.test.config.AutowiringSpringBeanJobFactory.createJobInstance(AutowiringSpringBeanJobFactory.java:27)
    at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:41)
    ... 2 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.test.jobs.FooJob.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)
    ... 6 common frames omitted

我到底做错了什么?如何使这个工作按计划自动运行,同时也能在手动请求时执行?
我正在使用 Spring Boot 1.5.9.RELEASE 和 Quartz 2.2.1

java.lang.NoSuchMethodException: com.test.jobs.FooJob.<init>() 是的,你没有一个无参数的构造函数。 - undefined
@Richardµś»scheduler.triggerJob(JobKey.jobKey("Your Job Key"));Ķ┐Öµ«Ąõ╗ŻńĀüõĖŹÕż¤ÕÉŚ’╝¤ - undefined
1个回答

4
正如@scary-wombat所说,你需要在FooJob中添加一个无参构造函数。你这种方法的问题是你不能以这种方式获得FooRepository
public FooJob() {
}

您有两个选择

1)如果FooRepository具有@Respository注释,则可以将@Autowired注释添加到构造函数中。

@Autowired
public FooJob(FooRepository fooRepo) {
        this.fooRepo = fooRepo;
}

感谢您使用@Repository注解,Spring会注意到它可以创建所需对象的实例以创建@service的实例。
2)您可以添加配置类。
@Configuration 
public class Config {}

你需要在那里创建你的服务实例 (FooJob)。

在我个人看来,第一种选项更好。

如果可以,请告诉我它是否有效!


我知道我来晚了,但我不理解第二个代码示例下面的部分。如何在扩展Job的类中正确地注入一个不同的类(而不是repo)? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接