injecter la référence de haricot dans un travail de quartz au spring?

J’ai réussi à configurer et à planifier un travail Quartz à l’aide du magasin persistant JobStoreTX au spring. Je n’utilise pas les jobs Quartz de Spring, car je dois les programmer dynamicment, au moment de l’exécution, et tous les exemples d’intégration de Spring avec Quartz trouvés dans les fichiers de configuration de Spring codaient en dur les shcedules … Je planifie le travail:

JobDetail emailJob = JobBuilder.newJob(EMailJob.class) .withIdentity("someJobKey", "immediateEmailsGroup") .storeDurably() .build(); SimpleTrigger sortinggger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity("someTriggerKey", "immediateEmailsGroup") .startAt(fireTime) .build(); // pass initialization parameters into the job emailJob.getJobDataMap().put(NotificationConstants.MESSAGE_PARAMETERS_KEY, messageParameters); emailJob.getJobDataMap().put(NotificationConstants.RECIPIENT_KEY, recipient); if (!scheduler.checkExists(jobKey) && scheduler.getTrigger(sortingggerKey) != null) { // schedule the job to run Date scheduleTime1 = scheduler.scheduleJob(emailJob, sortinggger); } 

EMailJob est un travail simple qui envoie un courrier électronique à l’aide de la classe JavaMailSenderImpl de Spring.

 public class EMailJob implements Job { @Autowired private JavaMailSenderImpl mailSenderImpl; public EMailJob() { } public void execute(JobExecutionContext context) throws JobExecutionException { .... try { mailSenderImpl.send(mimeMessage); } catch (MessagingException e) { .... throw new JobExecutionException("EMailJob failed: " + jobKey.getName(), e); } logger.info("EMailJob finished OK"); } 

Le problème est que je dois obtenir une référence à une instance de cette classe (JavaMailSenderImpl) dans ma classe EMailJob. Quand j’essaye de l’injecter comme ceci:

 @Autowired private JavaMailSenderImpl mailSenderImpl; 

il n’est pas injecté – la référence est NULL. Je suppose que cela se produit car ce n’est pas Spring qui instancie la classe EMailJob, mais Quartz et Quartz ne connaissent rien à l’dependency injection …

Y a-t-il un moyen de forcer cette injection?

Merci!

Mise à jour 1: @Aaron: voici une partie pertinente du stacktrace du démarrage, qui montre que l’EMailJob a été instancié deux fois:

 2011-08-15 14:16:38,687 [main] INFO org.springframework.context.support.GenericApplicationContext - Bean 'org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#0' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 2011-08-15 14:16:38,734 [main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1328c7a: defining beans [...]; root of factory hierarchy 2011-08-15 14:16:39,734 [main] INFO com.cambridgedata.notifications.EMailJob - EMailJob() - initializing ... 2011-08-15 14:16:39,937 [main] INFO org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Validated configuration atsortingbutes 2011-08-15 14:16:40,078 [main] INFO org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Validated configuration atsortingbutes 2011-08-15 14:16:40,296 [main] INFO org.springframework.jdbc.datasource.init.ResourceDatabasePopulator - Executing SQL script from class path resource ... 2011-08-15 14:17:14,031 [main] INFO com.mchange.v2.log.MLog - MLog clients using log4j logging. 2011-08-15 14:17:14,109 [main] INFO com.mchange.v2.c3p0.C3P0Registry - Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10] 2011-08-15 14:17:14,171 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2011-08-15 14:17:14,171 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.0.1 created. 2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Using thread monitor-based data access locking (synchronization). 2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - JobStoreTX initialized. 2011-08-15 14:17:14,187 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.0.1) 'NotificationsScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads. Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered. 2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'NotificationsScheduler' initialized from the specified file : 'spring/quartz.properties' from the class resource path. 2011-08-15 14:17:14,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.0.1 2011-08-15 14:17:14,234 [main] INFO com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 2sajb28h1lcabf28k3nr1|13af084, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 2sajb28h1lcabf28k3nr1|13af084, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/2010rewrite2, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 5, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> select 0 from dual, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ] 2011-08-15 14:17:14,312 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Freed 0 sortingggers from 'acquired' / 'blocked' state. 2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovering 0 jobs that were in-progress at the time of the last shut-down. 2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovery complete. 2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 'complete' sortingggers. 2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job ensortinges. 2011-08-15 14:17:14,328 [main] INFO org.quartz.core.QuartzScheduler - Scheduler NotificationsScheduler_$_NON_CLUSTERED started. 2011-08-15 14:17:14,515 [NotificationsScheduler_QuartzSchedulerThread] INFO com.cambridgedata.notifications.EMailJob - EMailJob() - initializing ... 

Merci!

Mise à jour n ° 2: @Ryan:

J’ai essayé d’utiliser la SpringBeanJobFactory comme suit:

        

Et j’ai modifié ma classe principale pour obtenir Scheduler à partir de cette usine, au lieu de Quartz ‘:

  @PostConstruct public void initNotificationScheduler() { try { //sf = new StdSchedulerFactory("spring/quartz.properties"); //scheduler = sf.getScheduler(); scheduler = schedulerFactoryBean.getScheduler(); scheduler.start(); .... 

Mais quand je lance l’application – obtenir des erreurs, voir ci-dessous. Voici le stacktrace du démarrage de Spring. Il semblerait que le Scheduler lui-même soit créé correctement, mais l’erreur survient lorsqu’il tente d’instancier mon EMailJob:

 2011-08-15 21:49:42,968 [main] INFO org.springframework.scheduling.quartz.SchedulerFactoryBean - Loading Quartz config from [class path resource [spring/quartz.properties]] 2011-08-15 21:49:43,031 [main] INFO com.mchange.v2.log.MLog - MLog clients using log4j logging. 2011-08-15 21:49:43,109 [main] INFO com.mchange.v2.c3p0.C3P0Registry - Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10] 2011-08-15 21:49:43,187 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.0.1 created. 2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Using thread monitor-based data access locking (synchronization). 2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - JobStoreTX initialized. 2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.0.1) 'schedulerFactoryBean' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 3 threads. Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is not clustered. 2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'schedulerFactoryBean' initialized from an externally provided properties instance. 2011-08-15 21:49:43,187 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.0.1 2011-08-15 21:49:43,187 [main] INFO org.quartz.core.QuartzScheduler - JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@566633 2011-08-15 21:49:43,265 [main] INFO com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hge13f8h1lsg7py1rg0iu0|1956391, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hge13f8h1lsg7py1rg0iu0|1956391, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/2010rewrite2, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 5, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> select 0 from dual, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> true, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ] 2011-08-15 21:49:43,343 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Freed 0 sortingggers from 'acquired' / 'blocked' state. 2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovering 0 jobs that were in-progress at the time of the last shut-down. 2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Recovery complete. 2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 'complete' sortingggers. 2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job ensortinges. 2011-08-15 21:49:43,359 [main] INFO org.quartz.core.QuartzScheduler - Scheduler schedulerFactoryBean_$_NON_CLUSTERED started. 2011-08-15 21:49:43,562 [schedulerFactoryBean_QuartzSchedulerThread] ERROR org.quartz.core.ErrorLogger - An error occured instantiating job to be executed. job= 'immediateEmailsGroup.DEFAULT.jobFor_1000new1' org.quartz.SchedulerException: Problem instantiating class 'com.cambridgedata.notifications.EMailJob' - [See nested exception: java.lang.AbstractMethodError: org.springframework.scheduling.quartz.SpringBeanJobFactory.newJob(Lorg/quartz/spi/TriggerFiredBundle;Lorg/quartz/Scheduler;)Lorg/quartz/Job;] at org.quartz.core.JobRunShell.initialize(JobRunShell.java:141) at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:381) Caused by: java.lang.AbstractMethodError: org.springframework.scheduling.quartz.SpringBeanJobFactory.newJob(Lorg/quartz/spi/TriggerFiredBundle;Lorg/quartz/Scheduler;)Lorg/quartz/Job; at org.quartz.core.JobRunShell.initialize(JobRunShell.java:134) 

Merci!

Juste un résumé de la solution fournie par jelies et quelques autres choses pour faciliter l’intégration de Spring + Quartz: http://codrspace.com/Khovansa/spring-quartz-with-a-database/

Vous pouvez utiliser cette SpringBeanJobFactory pour générer automatiquement des objects quartz avec Spring:

 import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.quartz.SpringBeanJobFactory; public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { 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); beanFactory.autowireBean(job); return job; } } 

Ensuite, attachez-le à votre SchedulerBean (dans ce cas, avec Java-config):

 @Bean public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean(); ... AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); quartzScheduler.setJobFactory(jobFactory); ... return quartzScheduler; } 

Travailler pour moi, en utilisant Spring-3.2.1 et quartz-2.1.6.

Découvrez l’intégralité de l’essentiel ici .

J’ai trouvé la solution dans cet article de blog

Je viens de mettre SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); comme première ligne de ma Job.execute(JobExecutionContext context) .

Le même problème a été résolu dans LINK :

Je pourrais trouver une autre option depuis la publication sur le forum Spring que vous pouvez transmettre une référence au contexte d’application Spring via SchedulerFactoryBean. Comme l’exemple ci-dessous:

        applicationContext  

Ensuite, en utilisant le code ci-dessous dans votre classe de travail, vous pouvez obtenir l’applicationContext et obtenir le bean souhaité.

 appCtx = (ApplicationContext)context.getScheduler().getContext().get("applicationContextSchedulerContextKey"); 

J’espère que cela aide. Vous pouvez obtenir plus d’informations à partir du blog de Mark Mclaren

Vous avez raison de penser que Spring vs. Quartz instancie la classe. Toutefois, Spring fournit des classes qui vous permettent d’injecter des dépendances primitives dans Quartz. Découvrez SchedulerFactoryBean.setJobFactory () avec le SpringBeanJobFactory . Essentiellement, à l’aide de SpringBeanJobFactory, vous activez l’dependency injection sur toutes les propriétés du travail, mais uniquement pour les valeurs figurant dans le contexte du planificateur Quartz ou dans le plan de données du travail . Je ne connais pas tous les styles de DI qu’il supporte (constructeur, annotation, setter …) mais je sais qu’il supporte l’injection de setter.

pour tous ceux qui essaieront cela dans le futur.

org.springframework.scheduling.quartz.JobDetailBean fournit la carte des objects et ces objects peuvent être des haricots de spring.

définir smth comme

         

et puis à l’intérieur

 public void executeInternal(JobExecutionContext context) 

appelez myBean = (myBean) context.getMergedJobDataMap().get("myBean"); et vous vous êtes tous mis. Je sais, ça a l’air moche, mais comme solution de contournement ça marche

 ApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(ContextLoaderListener .getCurrentWebApplicationContext().getServletContext()); Bean bean = (Bean) springContext.getBean("beanName"); bean.method(); 

Merci Rippon! J’ai enfin obtenu ce résultat après de nombreuses difficultés et ma solution est très proche de ce que vous proposiez! La clé était de créer mon propre Job pour étendre QuartzJobBean et d’utiliser schedulerContextAsMap.

Je suis parti sans spécifier la propriété applicationContextSchedulerContextKey – cela fonctionnait sans moi pour moi.

Pour le bénéfice des autres, voici la configuration finale qui a fonctionné pour moi:

                                       

Notez que le bean “mailService” est mon propre bean de service, géré par Spring. J’ai pu y accéder dans mon Job comme suit:

  public void executeInternal(JobExecutionContext context) throws JobExecutionException { logger.info("EMailJob started ..."); .... SchedulerContext schedulerContext = null; try { schedulerContext = context.getScheduler().getContext(); } catch (SchedulerException e1) { e1.printStackTrace(); } MailService mailService = (MailService)schedulerContext.get("mailService"); .... 

Et cette configuration m’a également permis de planifier les travaux de manière dynamic, en utilisant des fabriques pour obtenir les déclencheurs et les JobDetails, et en définissant les parameters requirejs par programmation:

  public NotificationScheduler(final Scheduler scheduler, final ObjectFactory jobDetailFactory, final ObjectFactory jobTriggerFactory) { this.scheduler = scheduler; this.jobDetailFactory = jobDetailFactory; this.jobTriggerFactory = jobTriggerFactory; ... // create a sortinggger SimpleTrigger sortinggger = jobTriggerFactory.getObject(); sortinggger.setRepeatInterval(0L); sortinggger.setStartTime(new Date()); // create job details JobDetail emailJob = jobDetailFactory.getObject(); emailJob.setName("new name"); emailJob.setGroup("immediateEmailsGroup"); ... 

Merci encore à tous ceux qui ont aidé,

Marina

Voici à quoi ressemble le code avec @Component:

Classe principale qui planifie le travail:

 public class NotificationScheduler { private SchedulerFactory sf; private Scheduler scheduler; @PostConstruct public void initNotificationScheduler() { try { sf = new StdSchedulerFactory("spring/quartz.properties"); scheduler = sf.getScheduler(); scheduler.start(); // test out sending a notification at startup, prepare some parameters... this.scheduleImmediateNotificationJob(messageParameters, recipients); try { // wait 20 seconds to show jobs logger.info("sleeping..."); Thread.sleep(40L * 1000L); logger.info("finished sleeping"); // executing... } catch (Exception ignore) { } } catch (SchedulerException e) { e.printStackTrace(); throw new RuntimeException("NotificationScheduler failed to resortingeve a Scheduler instance: ", e); } } public void scheduleImmediateNotificationJob(){ try { JobKey jobKey = new JobKey("key"); Date fireTime = DateBuilder.futureDate(delayInSeconds, IntervalUnit.SECOND); JobDetail emailJob = JobBuilder.newJob(EMailJob.class) .withIdentity(jobKey.toSsortingng(), "immediateEmailsGroup") .build(); TriggerKey sortingggerKey = new TriggerKey("sortingggerKey"); SimpleTrigger sortinggger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity(sortingggerKey.toSsortingng(), "immediateEmailsGroup") .startAt(fireTime) .build(); // schedule the job to run Date scheduleTime1 = scheduler.scheduleJob(emailJob, sortinggger); } catch (SchedulerException e) { logger.error("error scheduling job: " + e.getMessage(), e); e.printStackTrace(); } } @PreDestroy public void cleanup(){ sf = null; try { scheduler.shutdown(); } catch (SchedulerException e) { e.printStackTrace(); } } 

Le EmailJob est le même que lors de ma première publication, à l’exception de l’annotation @Component:

 @Component public class EMailJob implements Job { @Autowired private JavaMailSenderImpl mailSenderImpl; ... } 

Et le fichier de configuration de Spring a:

 ...         ...    

Merci pour votre aide!

Marina

Une solution simple consiste à définir le haricot de spring dans la carte des données du travail, puis à récupérer le bean dans la classe de travaux, par exemple

 // the class sets the configures the MyJob class SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); Date startTime = DateBuilder.nextGivenSecondDate(null, 15); JobDetail job = newJob(MyJob.class).withIdentity("job1", "group1").build(); job.getJobDataMap().put("processDataDAO", processDataDAO); 

`

  // this is MyJob Class ProcessDataDAO processDataDAO = (ProcessDataDAO) jec.getMergedJobDataMap().get("processDataDAO"); 

Une solution de Hary https://stackoverflow.com/a/37797575/4252764 fonctionne très bien. C’est plus simple, ne nécessite pas autant de grains spéciaux et prend en charge plusieurs déclencheurs et tâches. Ajoutez simplement que le travail de Quartz peut être générique, avec des tâches spécifiques implémentées comme des haricots de spring ordinaires.

 public interface BeanJob { void executeBeanJob(); } public class GenericJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap dataMap = context.getMergedJobDataMap(); ((BeanJob)dataMap.get("beanJob")).executeBeanJob(); } } @Component public class RealJob implements BeanJob { private SomeService service; @Autowired public RealJob(SomeService service) { this.service = service; } @Override public void executeBeanJob() { //do do job with service } } 

Une manière simple de le faire serait d’annoter les annotations de Quartz Jobs avec @Component , puis Spring ferait toute la magie DI pour vous, car elle est maintenant reconnue comme un bean Spring. J’ai dû faire quelque chose de similaire pour un aspect AspectJ – ce n’était pas un bean Spring tant que je ne l’avais pas annoté avec le stéréotype Spring @Component .

Assurez-vous que votre

 AutowiringSpringBeanJobFactory extends SpringBeanJobFactory 

la dépendance est extraite de

  "org.springframework:spring-context-support:4..." 

et PAS de

  "org.springframework:spring-support:2..." 

Il voulait que je l’utilise

 @Override public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) 

au lieu de

 @Override protected Object createJobInstance(final TriggerFiredBundle bundle) 

ainsi échouait à créer automatiquement une instance de travail.

Lorsque vous utilisez déjà AspectJ réel dans votre projet, vous pouvez alors annoter la classe du bean de travail avec @Configurable . Alors Spring va injecter dans cette classe, même si elle est construite via new

J’ai fait face à un problème similaire et en suis sorti avec l’approche suivante:

            

Dans le code ci-dessus, j’injecte le bean dao.DAOFramework dans le bean JobA et à l’intérieur de la méthode ExecuteInternal, vous pouvez obtenir un bean injecté comme:

  daoFramework = (DAOFramework)context.getMergedJobDataMap().get("daoBean"); 

J’espère que ça aide! Je vous remercie.

La solution ci-dessus est excellente mais dans mon cas, l’injection ne fonctionnait pas. Je devais plutôt utiliser autowireBeanProperties, probablement en raison de la configuration de mon contexte:

 import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.quartz.SpringBeanJobFactory; public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { 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); //beanFactory.autowireBean(job); beanFactory.autowireBeanProperties(job, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); return job; } } 

C’est la bonne réponse http://stackoverflow.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030#15211030 . et travaillera pour la plupart des gens. Mais si votre fichier web.xml ne connaît pas tous les fichiers applicationContext.xml, le travail quartz ne pourra pas appeler ces beans. J’ai dû faire une couche supplémentaire pour injecter des fichiers applicationContext supplémentaires

 public class MYSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { try { PathMatchingResourcePatternResolver pmrl = new PathMatchingResourcePatternResolver(context.getClassLoader()); Resource[] resources = new Resource[0]; GenericApplicationContext createdContext = null ; resources = pmrl.getResources( "classpath*:my-abc-integration-applicationContext.xml" ); for (Resource r : resources) { createdContext = new GenericApplicationContext(context); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(createdContext); int i = reader.loadBeanDefinitions(r); } createdContext.refresh();//important else you will get exceptions. beanFactory = createdContext.getAutowireCapableBeanFactory(); } catch (IOException e) { e.printStackTrace(); } } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } } 

You can add any number of context files you want your quartz to be aware of.

This is a quite an old post which is still useful. All the solutions that proposes these two had little condition that not suite all:

  • SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); This assumes or requires it to be a spring – web based project
  • AutowiringSpringBeanJobFactory based approach mentioned in previous answer is very helpful, but the answer is specific to those who don’t use pure vanilla quartz api but rather Spring’s wrapper for the quartz to do the same.

If you want to remain with pure Quartz implementation for scheduling(Quartz with Autowiring capabilities with Spring), I was able to do it as follows:

I was looking to do it quartz way as much as possible and thus little hack proves helpful.

  public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory{ private AutowireCapableBeanFactory beanFactory; public AutowiringSpringBeanJobFactory(final ApplicationContext applicationContext){ beanFactory = applicationContext.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); beanFactory.initializeBean(job, job.getClass().getName()); return job; } } @Configuration public class SchedulerConfig { @Autowired private ApplicationContext applicationContext; @Bean public AutowiringSpringBeanJobFactory getAutowiringSpringBeanJobFactory(){ return new AutowiringSpringBeanJobFactory(applicationContext); } } private void initializeAndStartScheduler(final Properties quartzProperties) throws SchedulerException { //schedulerFactory.initialize(quartzProperties); Scheduler quartzScheduler = schedulerFactory.getScheduler(); //Below one is the key here. Use the spring autowire capable job factory and inject here quartzScheduler.setJobFactory(autowiringSpringBeanJobFactory); quartzScheduler.start(); } 

quartzScheduler.setJobFactory(autowiringSpringBeanJobFactory); gives us an autowired job instance. Since AutowiringSpringBeanJobFactory implicitly implements a JobFactory , we now enabled an auto-wireable solution. J’espère que cela t’aides!

All those solutions above doesn’t work for me with Spring 5 and Hibernate 5 and Quartz 2.2.3 when I want to call transactional methods!

I therefore implemented this solution which automatically starts the scheduler and sortingggers the jobs. I found a lot of that code at dzone . Because I don’t need to create sortingggers and jobs dynamically I wanted the static sortingggers to be pre defined via Spring Configuration and only the jobs to be exposed as Spring Components.

My basic configuration look like this

 @Configuration public class QuartzConfiguration { @Autowired ApplicationContext applicationContext; @Bean public SchedulerFactoryBean scheduler(@Autowired JobFactory jobFactory) throws IOException { SchedulerFactoryBean sfb = new SchedulerFactoryBean(); sfb.setOverwriteExistingJobs(true); sfb.setAutoStartup(true); sfb.setJobFactory(jobFactory); Trigger[] sortingggers = new Trigger[] { cronTriggerTest().getObject() }; sfb.setTriggers(sortingggers); return sfb; } @Bean public JobFactory cronJobFactory() { AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } @Bean public CronTriggerFactoryBean cronTriggerTest() { CronTriggerFactoryBean tfb = new CronTriggerFactoryBean(); tfb.setCronExpression("0 * * ? * * *"); JobDetail jobDetail = JobBuilder.newJob(CronTest.class) .withIdentity("Testjob") .build() ; tfb.setJobDetail(jobDetail); return tfb; } } 

As you can see, you have the scheduler and a simple test sortinggger which is defined via a cron expression. You can obviously choose whatever scheduling expression you like. You then need the AutowiringSpringBeanJobFactory which goes like this

 public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { @Autowired private ApplicationContext applicationContext; private SchedulerContext schedulerContext; @Override public void setApplicationContext(final ApplicationContext context) { this.applicationContext = context; } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { Job job = applicationContext.getBean(bundle.getJobDetail().getJobClass()); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap()); pvs.addPropertyValues(bundle.getTrigger().getJobDataMap()); if (this.schedulerContext != null) { pvs.addPropertyValues(this.schedulerContext); } bw.setPropertyValues(pvs, true); return job; } public void setSchedulerContext(SchedulerContext schedulerContext) { this.schedulerContext = schedulerContext; super.setSchedulerContext(schedulerContext); } } 

In here you wire your normal application context and your job together. This is the important gap because normally Quartz starts it’s worker threads which have no connection to your application context. That is the reason why you can’t execute Transactional mehtods. The last thing missing is a job. It can look like that

 @Component public class CronTest implements Job { @Autowired private MyService s; public CronTest() { } @Override public void execute(JobExecutionContext context) throws JobExecutionException { s.execute(); } } 

It’s not a perfect solution because you an extra class only for calling your service method. But nevertheless it works.