首页 文章

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

提问于
浏览
2

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

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

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 方法我很难编写我的 Spring 季批处理作业名称,但在我的项目中我们有近800个工作,因此根据我们需要制作800个包装类 .

请帮助我,如何通过制作泛型类来解决这个问题 .

1 回答

  • 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);
            }
        }
    }
    

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

    对于您发布的示例,以下内容将在触发启动时启动 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 Batch自动连接所需的基础架构bean .

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

    Note: 这是从头顶输入的,我实际上没有对此进行测试,但至少应该让你知道如何做到这一点 .

相关问题