tag mvc form spring quartz-scheduler inject

spring - mvc - ¿inyectar referencia de frijol en un trabajo de Quartz en primavera?



spring mvc tag select (18)

Logré configurar y programar un trabajo de Quartz usando la tienda persistente JobStoreTX en Spring. No uso los trabajos de Spring''s Quartz, porque necesito programarlos dinámicamente, en tiempo de ejecución, y todos los ejemplos de integración de Spring con Quartz que encontré fueron difíciles de codificar los shcedules en los archivos de configuración de Spring ... De todos modos, aquí está cómo Programo el trabajo:

JobDetail emailJob = JobBuilder.newJob(EMailJob.class) .withIdentity("someJobKey", "immediateEmailsGroup") .storeDurably() .build(); SimpleTrigger trigger = (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(triggerKey) != null) { // schedule the job to run Date scheduleTime1 = scheduler.scheduleJob(emailJob, trigger); }

El EMailJob es un trabajo simple que envía correos electrónicos utilizando la clase 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"); }

El problema es que necesito obtener una referencia a una instancia de esta clase (JavaMailSenderImpl) en mi clase EMailJob. Cuando intento inyectarlo así:

@Autowired private JavaMailSenderImpl mailSenderImpl;

no está inyectado, la referencia es NULL. Asumo que esto está sucediendo porque no es Spring quien crea la clase EMailJob, sino Quartz, y Quartz no sabe nada sobre la inyección de dependencia ...

Entonces, ¿hay alguna forma de forzar esta inyección?

¡Gracias!

Actualización 1: @Aaron: aquí hay una parte relevante de stacktrace de la puesta en marcha, que muestra que EMailJob fue instanciado dos veces:

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 attributes 2011-08-15 14:16:40,078 [main] INFO org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Validated configuration attributes 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 triggers 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'' triggers. 2011-08-15 14:17:14,328 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job entries. 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 ...

¡Gracias!

Actualización # 2: @Ryan:

Traté de usar SpringBeanJobFactory de la siguiente manera:

<bean id="jobFactoryBean" class="org.springframework.scheduling.quartz.SpringBeanJobFactory"> </bean> <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="configLocation" value="classpath:spring/quartz.properties"/> <property name="jobFactory" ref="jobFactoryBean"/> </bean>

Y modifiqué mi clase principal para obtener un Scheduler de esta fábrica, en lugar de Quartz '':

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

Pero cuando ejecuto la aplicación, obtengo los errores, vea abajo. Aquí está el stacktrace del inicio de Spring. Parece que el Programador mismo está bien creado, pero el error aparece cuando intenta crear una instancia de mi 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 triggers 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'' triggers. 2011-08-15 21:49:43,359 [main] INFO org.quartz.impl.jdbcjobstore.JobStoreTX - Removed 0 stale fired job entries. 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)

¡Gracias!


Acabo de poner SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); como primera línea de mi Job.execute(JobExecutionContext context) .


Aquí es cómo se ve el código con @Component:

Clase principal que programa el trabajo:

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 retrieve 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.toString(), "immediateEmailsGroup") .build(); TriggerKey triggerKey = new TriggerKey("triggerKey"); SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity(triggerKey.toString(), "immediateEmailsGroup") .startAt(fireTime) .build(); // schedule the job to run Date scheduleTime1 = scheduler.scheduleJob(emailJob, trigger); } 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(); } }

El EmailJob es el mismo que en mi primera publicación a excepción de la anotación @Component:

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

Y el archivo de configuración de Spring tiene:

... <context:property-placeholder location="classpath:spring/*.properties" /> <context:spring-configured/> <context:component-scan base-package="com.mybasepackage"> <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" /> </context:component-scan> <bean id="mailSenderImpl" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="${mail.host}"/> <property name="port" value="${mail.port}"/> ... </bean> <bean id="notificationScheduler" class="com.mybasepackage.notifications.NotificationScheduler"> </bean>

¡Gracias por toda la ayuda!

Puerto pequeño


Asegúrese de que su

AutowiringSpringBeanJobFactory extends SpringBeanJobFactory

la dependencia se extrae de

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

y NO de

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

Quería que lo usara

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

en lugar de

@Override protected Object createJobInstance(final TriggerFiredBundle bundle)

por lo que no se pudo autoinstalar la instancia de trabajo.


Cuando ya usas AspectJ real en tu proyecto, puedes anotar la clase de bean de trabajo con @Configurable . Entonces Spring inyectará en esta clase, incluso si está construido a través de


El mismo problema se ha resuelto en LINK :

Pude encontrar otra opción de post en el foro de Spring que puede pasar una referencia al contexto de la aplicación Spring a través de SchedulerFactoryBean. Como el ejemplo que se muestra a continuación:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <propertyy name="triggers"> <list> <ref bean="simpleTrigger"/> </list> </property> <property name="applicationContextSchedulerContextKey"> <value>applicationContext</value> </property>

Luego, utilizando el código siguiente en su clase de trabajo, puede obtener el ApplicationContext y obtener el bean que desee.

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

Espero eso ayude. Puede obtener más información de Mark Mclaren''sBlog


Enfrenté el problema similar y salí de él con el siguiente enfoque:

<!-- Quartz Job --> <bean name="JobA" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- <constructor-arg ref="dao.DAOFramework" /> --> <property name="jobDataAsMap"> <map> <entry key="daoBean" value-ref="dao.DAOFramework" /> </map> </property> <property name="jobClass" value="com.stratasync.jobs.JobA" /> <property name="durability" value="true"/> </bean>

En el código anterior, inyecté dao.DAOFramework bean en JobA bean y en el interior del método ExecuteInternal se puede inyectar bean como:

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

¡Espero que ayude! Gracias.


Esta es la respuesta correcta http://.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030#15211030 . y funcionará para la mayoría de la gente. Pero si su web.xml no conoce todos los archivos de applicationContext.xml, el trabajo de cuarzo no podrá invocar esos beans. Tuve que hacer una capa adicional para inyectar archivos applicationContext adicionales

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.


Gracias, Rippon! Finalmente he conseguido que esto funcione también, después de muchas dificultades, ¡y mi solución está muy cerca de lo que sugeriste! La clave fue hacer mi propio trabajo para extender QuartzJobBean y usar el schedulerContextAsMap.

Me escapé sin especificar la propiedad applicationContextSchedulerContextKey; funcionó sin mí.

Para el beneficio de otros, aquí está la configuración final que me ha funcionado:

<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="configLocation" value="classpath:spring/quartz.properties"/> <property name="jobFactory"> <bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory" /> </property> <property name="schedulerContextAsMap"> <map> <entry key="mailService" value-ref="mailService" /> </map> </property> </bean> <bean id="jobTriggerFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"> <property name="targetBeanName"> <idref local="jobTrigger" /> </property> </bean> <bean id="jobTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean" scope="prototype"> <property name="group" value="myJobs" /> <property name="description" value="myDescription" /> <property name="repeatCount" value="0" /> </bean> <bean id="jobDetailFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"> <property name="targetBeanName"> <idref local="jobDetail" /> </property> </bean> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean" scope="prototype"> <property name="jobClass" value="com.cambridgedata.notifications.EMailJob" /> <property name="volatility" value="false" /> <property name="durability" value="false" /> <property name="requestsRecovery" value="true" /> </bean> <bean id="notificationScheduler" class="com.cambridgedata.notifications.NotificationScheduler"> <constructor-arg ref="quartzScheduler" /> <constructor-arg ref="jobDetailFactory" /> <constructor-arg ref="jobTriggerFactory" /> </bean>

Observe que el bean ''mailService'' es mi propio bean de servicio, administrado por Spring. Pude acceder a él en mi trabajo de la siguiente manera:

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"); ....

Y esta configuración también me permitió realizar tareas dinámicamente planificadoras, al usar fábricas para obtener desencadenantes y detalles de trabajo y establecer los parámetros requeridos sobre ellos programáticamente:

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

Muchas gracias otra vez a todos los que ayudaron,

Puerto pequeño


La solución anterior es excelente, pero en mi caso la inyección no funcionaba. Necesitaba usar autowireBeanProperties, probablemente debido a la forma en que está configurado mi contexto:

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; } }


Puede usar este SpringBeanJobFactory para autoaumentar automáticamente los objetos de cuarzo usando 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; } }

Luego, adjúntelo a su SchedulerBean (en este caso, con Java-config):

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

Trabajando para mí, usando spring-3.2.1 y quartz-2.1.6.

Mira la esencia completa here .

Encontré la solución en esta publicación de blog



Tienes razón en tu suposición de que Spring vs. Quartz crea una instancia de la clase. Sin embargo, Spring proporciona algunas clases que le permiten realizar una inyección de dependencia primitiva en Quartz. Consulte SchedulerFactoryBean.setJobFactory() junto con SpringBeanJobFactory . Básicamente, al usar SpringBeanJobFactory, habilita la inyección de dependencia en todas las propiedades del trabajo, pero solo para los valores que están en el contexto del programador de Quartz o en el mapa de datos del trabajo . No sé a qué todos los estilos DI admite (constructor, anotación, setter ...) pero sí sé que admite la inyección de setter.


Una forma simple de hacerlo sería simplemente anotar Quartz Jobs con la anotación @Component , y luego Spring hará toda la magia DI por usted, ya que ahora se reconoce como Spring Bean. Tuve que hacer algo similar para un aspecto AspectJ : no fue un Spring Bean hasta que lo @Component con el estereotipo Spring @Component .


Una solución simple es establecer el bean de primavera en el mapa de datos de trabajo y luego recuperar el bean en la clase de trabajo, por ejemplo

// 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");


para todos los que intenten esto en el futuro.

org.springframework.scheduling.quartz.JobDetailBean proporciona un mapa de objetos y esos objetos pueden ser de primavera.

definir como smth

<bean name="myJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="my.cool.class.myCoolJob" /> <property name="jobDataAsMap"> <map> <entry key="myBean" value-ref="myBean" /> </map> </property> </bean>

y luego, dentro

public void executeInternal(JobExecutionContext context)

llame a myBean = (myBean) context.getMergedJobDataMap().get("myBean"); y todo listo Lo sé, parece feo, pero como solución funciona


A solution from Hary https://.com/a/37797575/4252764 works very well. It''s simpler, doesn''t need so many special factory beans, and support multiple triggers and jobs. Would just add that Quartz job can be made to be generic, with specific jobs implemented as regular Spring beans.

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 } }


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.

Si desea permanecer con la implementación pura de Quartz para la programación (Quartz con capacidades de Autowiring con Spring), pude hacerlo de la siguiente manera:

Estaba buscando hacerlo de cuarzo tanto como fuera posible y, por lo tanto, poco hack resulta útil.

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);nos da una instancia de trabajo autocableado Como AutowiringSpringBeanJobFactoryimplementa implícitamente a JobFactory, ahora habilitamos una solución autoendustable. ¡Espero que esto ayude!


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