java - programadas - Spring Boot: uso de @Service en la ejecución del trabajo de Quartz
spring quartz ejemplo (2)
En una aplicación, como la convertí de una aplicación web Spring clásica (implementada en un sistema Tomcat) a una aplicación Spring Boot (V1.2.1), tengo el problema de que los trabajos programados basados en Quartz ya no funcionan.
Programa estos trabajos de Quartz como este:
// My own Schedule object which holds data about what to schedule when
Schedule schedule = scheduleService.get(id of the schedule);
String scheduleId = schedule.getId();
JobKey jobKey = new JobKey(scheduleId);
TriggerKey triggerKey = new TriggerKey(scheduleId);
JobDataMap jobData = new JobDataMap();
jobData.put("scheduleId", scheduleId);
JobBuilder jobBuilder = JobBuilder.newJob(ScheduledActionRunner.class)
.withIdentity(jobKey)
.withDescription(schedule.getName())
.usingJobData(jobData);
JobDetail job = jobBuilder.build();
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger()
.forJob(jobKey)
.withIdentity(triggerKey)
.withDescription(schedule.getName());
triggerBuilder = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.toCronExpression()));
Trigger trigger = triggerBuilder.build();
org.quartz.Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.scheduleJob(job, trigger);
ScheduledActionRunner
:
@Component
public class ScheduledActionRunner extends QuartzJobBean {
@Autowired
private ScheduleService scheduleService;
public ScheduledActionRunner() {
}
@Override
public void executeInternal(final JobExecutionContext context) throws JobExecutionException {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
final JobDataMap jobDataMap = context.getMergedJobDataMap();
final String scheduleId = jobDataMap.getString("scheduleId");
final Schedule schedule = scheduleService.get(scheduleId);
// here it goes BANG since scheduleService is null
}
}
ScheduleService
es un servicio clásico de Spring que obtiene datos de Hibernate. Como dije antes, funcionó bien hasta que me mudé a Spring Boot.
Cuando implementé este código con la aplicación clásica de Spring, SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
hizo el truco para encargarse de autocablear el servicio.
¿Qué se necesita para que esto vuelva a funcionar en el entorno Spring Boot?
Editar:
Al final, decidí alejarme del uso de Quartz a favor de Spring''s ThreadPoolTaskScheduler. El código se simplificó mucho y funciona como se esperaba.
SpringBeanAutowiringSupport utiliza el contexto de la aplicación web, que no está disponible en su caso. Si necesita un grano manejado por resorte en el cuarzo, debe usar el soporte de cuarzo provisto por la primavera. Esto le dará acceso completo a todos los beans administrados. Para obtener más información, consulte la sección de cuarzo en los documentos de primavera en http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html . Consulte también el siguiente ejemplo de uso de cuarzo con frijoles administrados por resorte. El ejemplo se basa en tu código. Por lo tanto, puede cambiar el primer fragmento de código (donde se realiza la inicialización de cuarzo) con alternativas de muelles alternativos.
Crear detalle de trabajo de fábrica
@Component
public class ScheduledActionRunnerJobDetailFactory extends JobDetailFactoryBean {
@Autowired
private ScheduleService scheduleService;
@Override
public void afterPropertiesSet() {
setJobClass(ScheduledActionRunner.class);
Map<String, Object> data = new HashMap<String, Object>();
data.put("scheduleService", scheduleService);
setJobDataAsMap(data);
super.afterPropertiesSet();
}
}
Crear la fábrica de disparadores
@Component
public class ActionCronTriggerFactoryBean extends CronTriggerFactoryBean {
@Autowired
private ScheduledActionRunnerJobDetailFactory jobDetailFactory;
@Value("${cron.pattern}")
private String pattern;
@Override
public void afterPropertiesSet() throws ParseException {
setCronExpression(pattern);
setJobDetail(jobDetailFactory.getObject());
super.afterPropertiesSet();
}
}
Y finalmente crea el SchedulerFactory
@Component
public class ActionSchedulerFactoryBean extends SchedulerFactoryBean {
@Autowired
private ScheduledActionRunnerJobDetailFactory jobDetailFactory;
@Autowired
private ActionCronTriggerFactoryBean triggerFactory;
@Override
public void afterPropertiesSet() throws Exception {
setJobDetails(jobDetailFactory.getObject());
setTriggers(triggerFactory.getObject());
super.afterPropertiesSet();
}
}
Mi respuesta no coincide por completo con su pregunta, pero Spring le muestra otra habilidad: iniciar el programador basado en cron-expression en cualquier servicio.
Usando Spring.Boot puedes configurar tu aplicación para usar el programador simplemente colocando
@EnableScheduling
public class Application{
....
Después de eso simplemente coloque la siguiente anotación en public
método public
(!) De @Service
@Service
public class MyService{
...
@Scheduled(cron = "0 * * * * MON-FRI")
public void myScheduledMethod(){
....
}