如何使用quartz scheduler动态配置spring作业

时间:2016-07-15 07:11:45

标签: java spring spring-mvc spring-batch quartz-scheduler

我是Spring Batch框架和石英调度程序的新手。我的任务是使用quartz调度程序动态安排新的Spring Batch作业。所有新的spring批处理作业条目都在我的数据库中,带有触发器表达式。问题是,对于来自数据库的每个新的Spring批处理作业,我们需要将其包含在quartz的调度程序作业中。所以意味着许多批处理作业类应该在那里包装它们并由石英调度程序运行。

quartz存储所有作业并触发进入其自己的数据库表。我在配置文件中配置。这项工作永远是石英的工作,而不是春季批量工作。 这是我的主要方法,在这里我将编写我的数据库连接代码以找出新的弹簧作业名称和触发器表达式,并将它们与石英计划程序绑定

 public static void main(String[] args) {
      try {

        ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");              
        JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
        JobLocator locator= (JobLocator) context.getBean("jobRegistry");
        Scheduler schedulerFactoryBean=(Scheduler) context.getBean("quartzSchedulerFactoryBean");

        JobDetail job = newJob(SpringBatchJob.class).withIdentity("myJob001", "group1").build();

        Trigger trigger1 =newTrigger().withIdentity("myTrigger001", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();

          schedulerFactoryBean.scheduleJob(job, trigger1);

           schedulerFactoryBean.start();              

      } catch (SchedulerException e) {
           e.printStackTrace();
      }
 }

在这里我们可以看到jobDetail是quartz作业,其执行方法用于运行spring批处理作业。

springBatchjob.java

public class SpringBatchJob implements Job {

private String jobName;
private String batchJob;

private JobLocator jobLocator;

private JobLauncher jobLauncher;

private File contentDirectory;

private String directoryPath = "inputFiles";

public void init(){
    contentDirectory = new File(directoryPath);
}

boolean fileFound = false;


public void performJob(String str) {}


public String getJobName() {
    return jobName;
}

public void setBatchJob(String batchJob) {
    this.batchJob = batchJob;
}

public void setJobName(String jobName) {
    this.jobName = jobName;
}

public void setJobLocator(JobLocator jobLocator) {
    this.jobLocator = jobLocator;
}

public void setJobLauncher(JobLauncher jobLauncher) {
    this.jobLauncher = jobLauncher;
}

@Override
public void execute(JobExecutionContext arg0) throws org.quartz.JobExecutionException {
    JobParameter jb= new JobParameter(5L);
    Map<String, JobParameter> map= new HashMap<>();
    map.put(jobName,jb);
     ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");             
     JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
        JobLocator locator= (JobLocator) context.getBean("jobRegistry");
        setJobLauncher(launcher);
        setJobLocator(locator);
        setJobName("helloWorldJob");
    // TODO Auto-generated method stub
    JobExecution result = null;
    try {
        result = jobLauncher.run(jobLocator.getJob(jobName), new JobParameters(map));
    } catch (JobExecutionAlreadyRunningException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JobRestartException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JobInstanceAlreadyCompleteException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (JobParametersInvalidException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchJobException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    System.out.println("ExamResult Job completetion details : "+result.toString());

}

这里的setJobName方法我很难编写我的春季批处理作业名称, 但是在我的项目中,我们有近800个工作岗位,因此我们需要制作800个包装类。

请帮助我,如何通过制作通用类来解决这个问题。

1 个答案:

答案 0 :(得分:5)

我真诚地希望你没有真正使用那个课程,它会最终消耗你所有的记忆,因为你一遍又一遍地重新创建你的应用程序。

Spring已经支持石英,尤其是以SpringBeanJobFactory形式构建的作业,您可以利用这些作业,特别是如果您通过一些自动布线功能扩展它。

public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private ApplicationContext context;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {

        Object object = super.createJobInstance(bundle);
        context.getAutowireCapableBeanFactory().autowireBean(object);
        return object;
    } 

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.context=applicationContext;
    }
}

然后像这样重写你的工作类

public class SpringBatchJob implements Job {

    private final Logger logger = LoggerFactory.getLogger(SpringBatchJob.class);

    private String jobName;

    @Autowired
    private JobLocator jobLocator;

    @Autowired
    private JobLauncher jobLauncher;

    @Override
    public void execute(JobExecutionContext context) throws org.quartz.JobExecutionException {

        JobDataMap JobDataMap = context.getMergedJobDataMap();
        JobParametersBuilder builder = new JobParametersBuilder();
        for (Map.Entry<String, Object) param : jobDataMap.entrySet()) {
            String key = param.getKey();
            Object val = param.getValue();
            builder.addString(key, String.valueOf(val)); // Or make it smarter by doing type detection.
        }

        Job jobToLaunch = jobLocator.getJob(jobName);
        JobExecution result;
        try {
            result = jobLauncher.run(jobToLaunch, builder.to);
        } catch (JobExecutionException e) {
            throw new org.quartz.JobExecutionException("Exception execution job '"+this.jobName+"'", e);
        } finally {
            logger.info("{}  Job completetion details ", this.jobName, result);
        }
    }
}

现在,您需要通过设置SchedulerFactoryBean属性来配置AutowiringSpringBeanJobFactory以使用jobFactory。完成后,您只需要适当配置石英作业。

对于您发布的示例,以下内容将在触发启动时启动helloWorldJob

public static void main(String[] args) {
      try {

        ApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");              
        JobLauncher launcher=(JobLauncher) context.getBean("jobLauncher");
        JobLocator locator= (JobLocator) context.getBean("jobRegistry");
        Scheduler schedulerFactoryBean=(Scheduler) context.getBean("quartzSchedulerFactoryBean");

        JobDetail job = newJob(SpringBatchJob.class)
                          .withIdentity("myJob001", "group1")
                          .usingJobData("jobName", "helloWorldJob")
                          .build();

        Trigger trigger1 =newTrigger().withIdentity("myTrigger001", "group1")
                          .startNow()
                          .withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever())
                          .build();

          schedulerFactoryBean.scheduleJob(job, trigger1);
          schedulerFactoryBean.start();              

      } catch (SchedulerException e) {
           e.printStackTrace();
      }
 }

注意.usingJobData("jobName", "helloWorldJob")SpringBeanJobFactory将尝试满足SpringBatchJob类上的所有setter方法。这有一个setJobName,在启动时会注入helloWorldJobAutowiringSpringBeanJobFactory扩展了该功能,以便自动连接Spring Batch所需的基础架构bean。

如果您需要将其他属性传递给Spring Batch作业(比如要使用的密钥或其他信息,只需添加另一个usingJobData("your-property", your-value)。修改后的SpringBatchJob会将所有夸脱作业参数映射到Spring Batch参数在开始工作之前。

注意:这是从我的头脑中输入的,我实际上没有对此进行过测试,但它至少应该让你知道如何做到这一点。