2017-09-26 2 views
3

Je suis d'essayer d'utiliser le planificateur de quartz au printemps. Je reçois ci-dessous exception lors de la configuration de plusieurs emploisAutowiring dans Quartz plusieurs emplois avec Spring Boot ne fonctionne pas

paramètre 0 de la méthode jobTrigger dans Job2 besoin d'un bean de type « org.quartz.JobDetail » qui n'a pas pu être trouvé.

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

Config classe

@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 de service a repo Spring JPA. La cause du problème est le service autowired ci-dessous. Si je supprime le service autowired ci-dessous des deux travaux, cela fonctionne très bien.

@Autorisé privé Service d'assistance;

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

Répondre

0

jobTrigger méthodes attendent comme argument un JobDetail mais les haricots passés sont de type JobDetailFactoryBean.

Peut-être que vous devriez faire les changements suivants ou quelque chose de similaire.

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

Et la même chose pour job2. Par ailleurs, vous mentionnez Spring - v1.5. Quelle version de Spring utilisez-vous réellement?

+0

« JobDetailFactoryBean permet une utilisation de type de haricot pour la configuration des instances JobDetail » http: //www.baeldung.com/spring-quartz-schedule. ma version de mauvais ressort est 4.2.9 – Zire

+0

Oui, mais vous essayez d'injecter le bean 'JobDetailFactoryBean' dans le paramètre de type' JobDetail'. Comment est-ce possible de travailler? Je pense que vous devriez obtenir jobDetail en utilisant la méthode 'getObject()' de 'JobDetailFactoryBean'. – lzagkaretos

+0

Je suppose que le printemps gère ça. sinon, il ne devrait pas fonctionner même pour un seul travail. Je reçois le problème seulement quand il y a plusieurs emplois. Toute la documentation et les articles que je peux trouver en ligne utilisent la même méthode. Si je supprime le service autowired et injecte manuellement le bean en utilisant le contexte de l'application, je n'obtiens pas le problème. – Zire

0

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

Essayez de changer les méthodes suivantes à l'intérieur de la classe d'emploi 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 Collection autowire ne fonctionne que dans 4.3

0

Je fait face à la même question et après un peu de lutte, je pouvais résoudre le problème. Il est probablement lié à l'annotation utilisée dans la classe d'emplois. Je vois que vous utilisez le @Component, comme c'était dans mon cas.La configuration du planificateur à quartz est annotée avec la balise @Configuration.

La solution consiste à annoter vos travaux avec la balise @Configuration. Ma conjecture est que les @Bean construits en classes annotées @Component ne sont pas complètement construites/mappées dans la phase où @Configuration sont annotées.

1

Ceci est une version modifiée du http://www.baeldung.com/spring-quartz-schedule que vous avez référencé pour la gestion de plusieurs travaux Quartz dans un fichier de configuration. Par souci de concision, je ne suis pas compris toute la classe QrtzSheduler juste le remplacement de la méthode de planificateur et l'utilisation de référence @Qualifier dans les éléments 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) { 

    ... 
} 
+0

C'est exactement ce dont j'avais besoin. Merci beaucoup! – rocotocloc