¿Cómo programar los trabajos de cron de Quartz al inicio de una aplicación Spring Boot?
Estoy integrando Quartz con Spring Boot y Postgres. He creado todas las tablas necesarias para el Quartz.
Problema: La aplicación se inicia pero el trabajo no se ejecuta según el cron.
Quiero que los trabajos se programen automáticamente al inicio y se ejecuten según la expresión del cron. Pero por ahora, la aplicación se inicia y no se dispara ninguna orden.
La clase QuartzJobFactory:
public class QuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {
beanFactory = applicationContext.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance (TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
La clase ConfigQuartz:
@Configuration
public class ConfigQuartz {
@Value("${quartz.dataSource.myDS.URL}")
String orgQuartzDatasourceMydsUrl;
@Value("${spring.datasource.username}")
String orgQuartzDatasourceMydsUser;
@Value("${spring.datasource.password}")
String orgQuartzDatasourceMydsPassword;
@Value("${quartz.enabled}")
Boolean isQuartzEnabled;
private static List<trigger> triggers = new ArrayList<>();
@Bean
public JobFactory jobFactory (ApplicationContext applicationContext) {
QuartzJobFactory sampleJobFactory = new QuartzJobFactory();
sampleJobFactory.setApplicationContext(applicationContext);
return sampleJobFactory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory)
throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(isQuartzEnabled);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
return factory;
}
public Properties setQuartzProperties () {
Properties properties = new Properties();
properties.setProperty("org.quartz.dataSource.myDS.URL", orgQuartzDatasourceMydsUrl);
properties.setProperty("org.quartz.dataSource.myDS.user", orgQuartzDatasourceMydsUser);
properties.setProperty("org.quartz.dataSource.myDS.password", orgQuartzDatasourceMydsPassword);
return properties;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
propertiesFactoryBean.setProperties(setQuartzProperties());
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
public static SimpleTriggerFactoryBean createTrigger (JobDetail jobDetail, long pollFrequencyMs, String triggerName) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(0L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
factoryBean.setName(triggerName);
factoryBean.setMisfireInstruction(
SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
return factoryBean;
}
public static CronTriggerFactoryBean createCronTrigger (JobDetail jobDetail, String cronExpression, String triggerName) throws Exception {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setCronExpression(cronExpression);
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
factoryBean.setName(triggerName);
try {
factoryBean.afterPropertiesSet();
} catch (ParseException e) {
throw new Exception(e.getMessage());
}
triggers.add(factoryBean.getObject());
return factoryBean;
}
public static JobDetailFactoryBean createJobDetail (Class jobClass) {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
factoryBean.setDurability(true);
return factoryBean;
}
}
La clase CronExpression:
public class CronExpression {
private static final Map<string, string=""> cronExpressionMap = ImmutableMap
.<string, string="">builder()
.put(TestJob.CLASS_NAME, "* 0 0 ? * * *")
.build();
public static String get (String key) {
return cronExpressionMap.get(key);
}
}
La clase TestJob:
@Component
@DisallowConcurrentExecution
public class TestJob implements Job {
public static final String CLASS_NAME = "TestJob";
private final String JOB_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_JOB_SUFFIX;
private final String TRIGGER_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_TRIGGER_SUFFIX;
@Override
public void execute (JobExecutionContext jobExecutionContext) throws JobExecutionException {
LocalDateTime start = LocalDateTime.now();
System.out.println("*************** execute method is running *******");
}
@Bean(name = JOB_BEAN_NAME)
public JobDetailFactoryBean sampleJob () {
return ConfigQuartz.createJobDetail(this.getClass());
}
@Bean(name = TRIGGER_BEAN_NAME)
public CronTriggerFactoryBean sampleJobTrigger (
@Qualifier(JOB_BEAN_NAME) JobDetailFactoryBean jobDetail) throws Exception {
return ConfigQuartz.createCronTrigger(jobDetail.getObject(), CronExpression.get(CLASS_NAME),
CLASS_NAME);
}
}
La clase principal:
“`
@EnableConfigurationProperties
@EntityScan(basePackages = {“com.example”})
@ComponentScan({“com.example”})
@SpringBootApplication
@EnableScheduling
public class QuartzSchedulerApplication {
public static void main (String[] args) {
SpringApplication</string,></string,>
davy.ai
El problema con el código dado es que aunque se han creado todas las tablas necesarias para Quartz, los trabajos no se están programando automáticamente al iniciar y no se están ejecutando según la expresión cron dada.
Para programar automáticamente trabajos al inicio y ejecutarlos según la expresión cron, podemos hacer los siguientes cambios en el código existente:
@Scheduled
a la claseTestJob
y proporcionar la expresión cron como parámetro a la anotación.createCronTrigger()
de la claseConfigQuartz
y reemplazarlo con un método@Bean
para cada trabajo. Añadir la anotación@Scheduled
a este método y proporcionar la expresión cron como parámetro a la anotación.org.quartz.jobStore.isClustered
en false en el archivoquartz.properties
.Con estos cambios, los trabajos se programarán automáticamente al inicio y se ejecutarán según las expresiones cron dadas. Las anotaciones
@Scheduled
proporcionan una forma sencilla de especificar el momento de la ejecución de tareas en una aplicación Spring boot.