У меня есть класс QuartzJobConfig
, где я зарегистрирую свой Spring-Quartz-Beans
.Как создать весеннюю фасоль динамическим способом. Использование Quartz SchedulerFactoryBean
Я следовал инструкциям SchedulerFactoryBean
, JobDetailFactoryBean
и CronTriggerFactoryBean
.
Мои вакансии настроены в файле yaml
за пределами приложения. Значит, я должен динамически создавать Beans при запуске приложения.
Моя конфигурация:
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
...
My Config Класс:
@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) просто сделать один раз. После первой итерации он больше не входит в метод jobTrigger(ch, jobConfig)
. (Более или менее ясно из-за названия компонента, если я прав)
Что я думал, потому что я использую Quartz factories
Весна. Метод jobDetailFactoryBean.setBeanName()
используется для создания большего количества бобов с разными именами.
Не знаю, как я могу решить эту проблему. Код работает, и первое созданное задание выполняется правильно. Но мне нужно больше рабочих мест.
Как я могу создать разные задания динамически?
Edit:
Мои полные классы конфигурации:
@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 Я попытался использовать область прототипа. Но его просто инициализация той же работы. Должен ли мой «Список» быть прототипом? –
Patrick
Каждый бит, который вы хотите иметь несколько экземпляров (ваша работа, триггеры), должен быть прототипом в этом сценарии, иначе он не будет работать. Таким образом, ваши «jobTrigger», а также «jobBean» должны быть прототипами в области ... Иначе это провалится. –