当前位置: 首页 > 知识库问答 >
问题:

如何利用quartz调度器动态配置spring作业

姜俊逸
2023-03-14

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

quartz将所有作业和触发器项存储到自己的数据库表中。我已在配置文件中对其进行了配置。该作业将始终是石英的作业,而不是spring批处理作业。这里是我的主要方法,这里我将编写我的数据库连接代码,找出新的springbatch作业名称和触发器表达式,并将它们与quartz schedular绑定

 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,它是石英作业,它的执行方法是用来运行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方法中,我对我的spring批处理作业名进行了硬编码,但在我的项目中,我们有将近800个作业,因此要想接近,我们需要制作800个包装器类。

请帮助我,如何通过做泛型类来解决这个问题。

共有1个答案

华良平
2023-03-14

我真诚地希望您不是真的在使用那个类,当您一遍又一遍地重新创建应用程序时,它最终会吃掉您所有的内存。

spring已经支持quartz,特别是以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);
        }
    }
}

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

对于您发布的示例,当HelloWorldJob被触发启动时,下面的示例将启动该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,它将在启动时注入HelloWorldJob。该功能通过autowiringSpringBeanJobFactory进行了扩展,以自动连接来自spring批处理的所需基础结构bean。

如果需要将其他属性传递给spring批处理作业(如要使用的键或其他信息,只需使用JobData(“your-property”,your-value)添加另一个修改后的SpringBatchJob将在启动该作业之前将所有quarts作业参数映射到spring批处理参数。

注意:这是从我的头顶打出来的,我没有实际测试过,但它至少应该给你一个如何做的想法。

 类似资料:
  • 我有一个web服务,它对某个作业进行动态调度。job是一个Java类,它扩展了Quartz job接口 我还公开了一个API,它接收一个jobId、cron表达式,并调度一个新的StartJob(它将具有接收到的ID)。下面是我的Spring配置: 我错过了什么?这样的配置正确吗?从工厂中检索到的作业和触发器是同一个类的新实例还是同一个类实例?

  • 相关: 我觉得我错过了什么?

  • 我想使用Quartz、Spring和Hibernate创建动态作业。用户与web服务交互以创建此类作业: NoaJobInstancesDAO是一个简单的DAO类,它利用了Hibernate的EntityManager: 问题是,当这个作业触发时,会抛出一个异常: 我不明白为什么!在Manager类中,我以这种方式安排作业 其中排定程序作为 Edit1:应用程序上下文的实例似乎正确。问题不可能在那

  • 我想使用Quartz和Oracle作为JobStore来安排作业。我看到了大多数使用RAMjobstore的示例(当然它不是持久的),但几乎没有任何一个可以帮助我满足Spring boot Quartz Oracle开发的需求。 如有任何指向代码示例或github项目的链接或帮助,将不胜感激。