web-dev-qa-db-fra.com

Le câblage automatique dans plusieurs travaux Quartz avec Spring Boot ne fonctionne pas

J'essaie d'utiliser un programmateur à quartz au printemps. Je reçois une exception ci-dessous lors de la configuration de plusieurs tâches 

Le paramètre 0 de la méthode jobTrigger dans Job2 nécessitait un bean de type 'org.quartz.JobDetail' qui était introuvable.

quartz - v2.3, ressort - v4.2.x

Classe de configuration

@Configuration
 public class SchedulerConfig {

private static final Logger LOG = LoggerFactory.getLogger(SchedulerConfig.class);

@Autowired
List<Trigger> triggers;

@Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
    AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    return jobFactory;
}

@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory)  throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
          factory.setAutoStartup(true);
    factory.setJobFactory(jobFactory);
         factory.setQuartzProperties(quartzProperties());
    if (triggers != null && !triggers.isEmpty()) {
         LOG.info("starting jobs... Total Triggers - " + triggers.size());
        factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
    }

    return factory;
}

@Bean
public Properties quartzProperties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
    propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
}


public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) {
    CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
    factoryBean.setJobDetail(jobDetail);
    factoryBean.setCronExpression(cronExpression);
    factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
    return factoryBean;
}

public static JobDetailFactoryBean createJobDetail(Class jobClass) {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(jobClass);
    factoryBean.setDurability(true);
    return factoryBean;
}

SpringBeanJobFactory

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

private static final Logger LOG = LoggerFactory.getLogger(AutowiringSpringBeanJobFactory.class);

private transient AutowireCapableBeanFactory beanFactory;

@Override
public void setApplicationContext(final ApplicationContext context) {
    beanFactory = context.getAutowireCapableBeanFactory();
}

@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
    final Object job = super.createJobInstance(bundle);
    LOG.info("create job instance");
    beanFactory.autowireBean(job);
    return job;
}

}

Job 1

@Component
@DisallowConcurrentExecution
public class Job1 implements Job {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Value("${schedule}")
private String frequency;

@Autowired
private Service service;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
    log.info("execute");
}

@Bean(name = "jobBean1")
public JobDetailFactoryBean job() {
    return SchedulerConfig.createJobDetail(this.getClass());
}

@Bean(name = "jobBean1Trigger")
public CronTriggerFactoryBean jobTrigger(@Qualifier("jobBean1")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency);
}

Job 2

@Component
@DisallowConcurrentExecution
public class Job2 implements Job {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Value("${schedule}")
private String frequency;

@Autowired
private Service service;

@Override
public void execute(JobExecutionContext jobExecutionContext) {
    log.info("execute");
}

@Bean(name = "jobBean2")
public JobDetailFactoryBean job() {
    return SchedulerConfig.createJobDetail(this.getClass());
}

@Bean(name = "jobBean2Trigger")
public CronTriggerFactoryBean jobTrigger(@Qualifier("jobBean2")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency);
}

La classe Service a des repos Spring JPA. La cause première du problème est le service auto-câblé ci-dessous. Si je supprime le service auto-câblé ci-dessous des deux tâches, cela fonctionne correctement.

@Autowired Service de service privé;

S'il n'y a qu'un seul travail avec ce bean auto-câblé, il n'y a pas d'exception. Comment configurer plusieurs travaux en utilisant la même dépendance auto-câblée? Quelle est la cause de ce problème?

5
Zire

Ceci est une version modifiée de http://www.baeldung.com/spring-quartz-schedule que vous avez référencée pour la gestion de plusieurs travaux Quartz dans un seul fichier de configuration. Par souci de brièveté, je n’inclus pas toute la classe QrtzSheduler, mais uniquement le remplacement de la méthode de planification et l’utilisation de la référence @Qualifier dans les déclencheurs:

...
@Bean
public Scheduler scheduler(Map<String, JobDetail> jobMap, Set<? extends Trigger> triggers) throws SchedulerException, IOException {

    StdSchedulerFactory factory = new StdSchedulerFactory();
    factory.initialize(new ClassPathResource("quartz.properties").getInputStream());

    logger.debug("Getting a handle to the Scheduler");
    Scheduler scheduler = factory.getScheduler();
    scheduler.setJobFactory(springBeanJobFactory());
    Map<JobDetail,Set<? extends Trigger>> triggersAndJobs = new HashMap<JobDetail,Set<? extends Trigger>>;
    for(JobDetail jobDetail : jobMap.getValues()){
        for(Trigger trigger : triggers){
            if(trigger.getJobKey().equals(jobDetail.getKey())){
               Set<Trigger> set = new HashSet<>();
               set.add(trigger);
               triggerAndJobs.put(jobDetail,set);
            }
        }
    }
    scheduler.scheduleJobs(triggersAndJobs, false);

    logger.debug("Starting Scheduler threads");
    scheduler.start();
    return scheduler;
}

@Bean(name="jobOne")
public JobDetail jobDetailOne() {

    ...
}

@Bean(name="jobTwo")
public JobDetail jobDetailTwo() {

   ...
}

@Bean
public Trigger triggerOne(@Qualifier("jobOne")JobDetail jobDetail) {

   ...
}

@Bean
public Trigger triggerTwo(@Qualifier("jobTwo")JobDetail jobDetail) {

   ...
}
2
Rob Cullen

Vous essayez d'utiliser la configuration de démarrage de printemps avec Spring 4.2.

Essayez de modifier les méthodes suivantes dans la classe de travail comme suit

@Bean(name = "jobBean1")
public JobDetail job() {
    return SchedulerConfig.createJobDetail(this.getClass()).getObject();
}

@Bean(name = "jobBean1Trigger")
public CronTrigger jobTrigger(@Qualifier("jobBean1")JobDetail jobDetail) {
    return SchedulerConfig.createCronTrigger(jobDetail, frequency).getObject();
}

Utilisez également le printemps 4.3 car vous avez besoin 

@Autowired
List<Trigger> triggers;

Je crois que Collection Autowire ne fonctionne qu'en 4.3

0
Shanoj S

Les méthodes jobTrigger prévoient comme argument une variable JobDetail mais les beans transmis sont de type JobDetailFactoryBean.

Peut-être devriez-vous apporter le changement suivant ou quelque chose de similaire.

@Bean(name = "jobBean1")
public JobDetail job() {
    return SchedulerConfig.createJobDetail(this.getClass()).getObject();
}

Et pareil pour job2.

En passant, Vous avez mentionné Spring - v1.5. Quelle version de Spring utilisez-vous réellement?

0
lzagkaretos

J'ai fait face au même problème et après un peu de difficulté, j'ai pu le résoudre. Il est probablement lié à l'annotation utilisée dans la classe de travail. Je vois que vous utilisez le @Component, comme c'était le cas dans mon cas. À la place, la configuration du planificateur à quartz est annotée avec la balise @Configuration

La solution consiste à annoter vos travaux avec la balise @Configuration. Je suppose que les @Bean construits dans les classes annotées @Component ne sont pas complètement construits/mappés dans la phase où les @Configuration annotés sont initialisés. 

0
NiVeR