【发布时间】:2016-12-07 16:15:26
【问题描述】:
我有一个QuartzJobConfig 课程,我在其中注册了我的Spring-Quartz-Beans。
我遵循了SchedulerFactoryBean、JobDetailFactoryBean和CronTriggerFactoryBean的指示。
我的作业在应用程序外部的yaml 文件中配置。意味着我必须在应用程序启动时动态创建 Bean。
我的配置:
channelPartnerConfiguration:
channelPartners:
- code: Job1
jobConfigs:
- schedule: 0 * * ? * MON-FRI
name: Job1 daily
hotel: false
allotment: true
enabled: true
- schedule: 30 * * ? * MON-FRI
name: Job2 weekly
hotel: true
allotment: false
enabled: true
...
我的配置类:
@Configuration
public class QuartzJobConfig implements IJobClass{
@Autowired
ChannelPartnerProperties channelPartnerProperties;
@Autowired
private ApplicationContext applicationContext;
@Bean
public SchedulerFactoryBean quartzScheduler() {
SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();
quartzScheduler.setOverwriteExistingJobs(true);
quartzScheduler.setSchedulerName("-scheduler");
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
quartzScheduler.setJobFactory(jobFactory);
// point 1
List<Trigger> triggers = new ArrayList<>();
for(ChannelPartner ch : channelPartnerProperties.getChannelPartners()){
for(JobConfig jobConfig : ch.getJobConfigs()){
triggers.add(jobTrigger(ch, jobConfig).getObject());
}
}
quartzScheduler.setTriggers(triggers.stream().toArray(Trigger[]::new));
return quartzScheduler;
}
@Bean
public JobDetailFactoryBean jobBean(ChannelPartner ch, JobConfig jobConfig) {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(findJobByConfig(jobConfig));
jobDetailFactoryBean.setGroup("mainGroup");
jobDetailFactoryBean.setName(jobConfig.getName());
jobDetailFactoryBean.setBeanName(jobConfig.getName());
jobDetailFactoryBean.getJobDataMap().put("channelPartner", ch);
return jobDetailFactoryBean;
}
@Bean
public CronTriggerFactoryBean jobTrigger(ChannelPartner ch, JobConfig jobConfig) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobBean(ch, jobConfig).getObject());
cronTriggerFactoryBean.setCronExpression(jobConfig.getSchedule());
cronTriggerFactoryBean.setGroup("mainGroup");
return cronTriggerFactoryBean;
}
@Override
public Class<? extends Job> findJobByConfig(JobConfig jobConfig) {
if(isAllotmentJob(jobConfig) && isHotelJob(jobConfig)){
return HotelAndAllotmentJob.class;
}
if(isAllotmentJob(jobConfig)){
return AllotmentJob.class;
}
if(isHotelJob(jobConfig)){
return HotelJob.class;
}
return HotelAndAllotmentJob.class;
}
private boolean isAllotmentJob(JobConfig jobConfig){
return jobConfig.isAllotment();
}
private boolean isHotelJob(JobConfig jobConfig) {
return jobConfig.isHotel();
}
}
我的问题是迭代(第 1 点)中 Bean 的创建只完成了一次。第一次迭代后,它不再进入jobTrigger(ch, jobConfig) 方法。 (如果我是对的,由于 bean 名称或多或少清楚)
我在想什么,因为我使用Spring的Quartz factoriesjobDetailFactoryBean.setBeanName()方法用于创建更多不同名称的bean。
不知道如何解决这个问题。代码正在运行,第一个创建的作业正在正确执行。但我需要更多工作。
如何以动态方式创建不同的作业?
编辑:
我的完整配置类:
@Configuration
@ConfigurationProperties(prefix = "channelPartnerConfiguration", locations = "classpath:customer/channelPartnerConfiguration.yml")
public class ChannelPartnerProperties {
@Autowired
private List<ChannelPartner> channelPartners;
public List<ChannelPartner> getChannelPartners() {
return channelPartners;
}
public void setChannelPartners(List<ChannelPartner> channelPartners) {
this.channelPartners = channelPartners;
}
}
@Configuration
public class ChannelPartner {
private String code;
private String contracts;
private Boolean includeSpecialContracts;
private String touroperatorCode = "EUTO";
@Autowired
private PublishConfig publishConfig;
@Autowired
private BackupConfig backupConfig;
@Autowired
private List<JobConfig> jobConfigs;
//getter/setter
@Configuration
public class JobConfig {
private String schedule;
private boolean hotelEDF;
private boolean allotmentEDF;
private boolean enabled;
private String name;
//getter/setter
添加project to github以便更好地理解问题
【问题讨论】:
-
您的方法标记为
@Bean,这意味着它们都是单例...如果您只想将其用作工厂方法,请将其标记为@Bean(scope="prototype")。 -
@M.Deinum 我尝试使用原型范围。但它只是初始化相同的工作。我的
List<JobConfig>应该是原型吗? -
您希望拥有多个实例(您的工作、触发器)的每个 bean 都需要在此场景中成为原型范围,否则它将无法工作。所以你的
jobTrigger和jobBean都必须是原型范围的......否则它会失败。 -
@M.Deinum 完全正确。你描述的工作流程就是这样发生的。但只有我在列表中的第一个 jobconfig 被多次注册。我在这里错过了什么?
-
如果你没有原型作用域的bean,它们是单例的,只会被创建一次......
标签: java spring spring-boot quartz-scheduler spring-bean