J'ai une classe QuartzJobConfig
où j'inscris mon Spring-Quartz-Beans
. J'ai suivi les instructions du SchedulerFactoryBean
, JobDetailFactoryBean
et CronTriggerFactoryBean
.Comment créer des haricots de printemps de manière dynamique. Utilisation de Quartz SchedulerFactoryBean
Mes tâches sont configurées dans un fichier yaml
en dehors de l'application. Moyens Je dois créer les Beans dynamiquement lorsque l'application démarre.
Ma config:
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
...
Ma config Classe:
@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();
}
}
Mon problème est que la création des haricots à l'intérieur de l'itération (point 1) est juste fait une seule fois. Après la première itération, il ne va plus dans la méthode jobTrigger(ch, jobConfig)
. (Plus ou moins claire en raison du nom de haricot si je suis à droite)
Ce que je pensais, parce que j'utilise la Quartz factories
du printemps la méthode jobDetailFactoryBean.setBeanName()
est utilisée pour créer plus de haricots avec des noms différents.
Vous ne savez pas comment résoudre ce problème. Le code fonctionne et le premier travail créé s'exécute correctement. Mais j'ai besoin de plus d'emplois.
Comment puis-je créer les différents travaux de manière dynamique?
Edit:
Mes cours complet de configuration:
@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
Ajouté project to github pour une meilleure compréhension du problème
Vous avez vos méthodes marquées '@ Bean' qui signifie que toutes sont des singletons ... Si vous voulez juste l'utiliser comme une méthode d'usine marquez-le' @Bean (scope = "prototype") '. –
@ M.Deinum J'ai essayé d'utiliser la portée du prototype. Mais c'est juste initialiser le même travail. Est-ce que mon 'List' devrait être prototype? –
Patrick
Chaque bean que vous voulez avoir plusieurs instances de (votre travail, triggers) doit être prototype dans ce scénario sinon cela ne fonctionnera pas. Donc à la fois votre 'jobTrigger' et' jobBean' doivent être protégés par un prototype ... Sinon, cela échouera. –