Programação na primavera com quartzo
1. Visão geral
Neste tutorial, construiremos umScheduler in Spring with Quartz simples.
Começaremos com um objetivo simples em mente - configurar facilmente um novo trabalho agendado.
1.1. Principais componentes da API Quartz
O quartzo possui uma arquitetura modular. Consiste em vários componentes básicos que podem ser combinados conforme necessário. Neste tutorial, vamos nos concentrar naqueles que são comuns a todos os trabalhos:Job,JobDetail,TriggereScheduler.
Embora usemos Spring para gerenciar o aplicativo, cada componente individual pode ser configurado de duas maneiras: a maneiraQuartz ou a maneiraSpring (usando suas classes de conveniência).
Abordaremos tanto quanto possível por uma questão de completude, mas qualquer um pode ser adotado. Vamos começar a construir, um componente de cada vez.
Leitura adicional:
Um guia para o Agendador de tarefas Spring
Um guia rápido e prático para agendar no Spring com o Task Scheduler
Planejamento no Java EE
Uma demonstração de como agendar tarefas no Java EE usando a anotação @Schedule e o serviço de timer.
Introdução ao Drools
Aprenda a usar Drools como um sistema de gerenciamento de regras de negócios (BRMS).
2. Job eJobDetail
2.1. Job
A API fornece uma interfaceJob com apenas um método -execute. Ela deve ser implementada pela classe que contém o trabalho real a ser feito, ou seja, a tarefa. Quando o gatilho de um job é disparado, o planejador invoca o métodoexecute, passando um objetoJobExecutionContext.
OJobExecutionContext fornece à instância do job informações sobre seu ambiente de tempo de execução, incluindo um identificador para o planejador, um identificador para o acionador e o objetoJobDetail do job.
Neste exemplo rápido - o trabalho delega a tarefa a uma classe de serviço: __
@Component
public class SampleJob implements Job {
@Autowired
private SampleJobService jobService;
public void execute(JobExecutionContext context) throws JobExecutionException {
jobService.executeSampleJob();
}
}
2.2. JobDetail
Enquanto o trabalho é o cavalo de batalha, o Quartz não armazena uma instância real da classe de trabalho. Em vez disso, podemos definir uma instância deJob usando a classeJobDetail. A classe do trabalho deve ser fornecida aoJobDetail para que ele saiba otype do trabalho a ser executado.
2.3. QuartzoJobBuilder
O QuartzJobBuilder fornece uma API de estilo construtor para construirJobDetail entidades.
@Bean
public JobDetail jobDetail() {
return JobBuilder.newJob().ofType(SampleJob.class)
.storeDurably()
.withIdentity("Qrtz_Job_Detail")
.withDescription("Invoke Sample Job service...")
.build();
}
2.4. PrimaveraJobDetailFactoryBean
JobDetailFactoryBean do Spring fornece o uso do estilo bean para configurar instâncias deJobDetail. Ele usa o nome do bean Spring como o nome do trabalho, se não for especificado de outra forma:
@Bean
public JobDetailFactoryBean jobDetail() {
JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(SampleJob.class);
jobDetailFactory.setDescription("Invoke Sample Job service...");
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
Uma nova instância deJobDetail é criada para cada execução do trabalho. O objetoJobDetail transmite as propriedades detalhadas do trabalho. Depois que a execução é concluída, as referências à instância são descartadas.
3. Desencadear
UmTrigger é o mecanismo para agendar umJob, ou seja, uma instânciaTrigger “dispara” a execução de um trabalho. Há uma separação clara de responsabilidades entreJob (noção de tarefa) eTrigger (mecanismo de agendamento).
Além deJob, o gatilho também precisa de umtype que pode ser escolhido com base nos requisitos de programação.
Digamos que queremos agendar nossa tarefa para executaronce every hour, indefinidamente - podemos usarTriggerBuilder de Quartz ouSimpleTriggerFactoryBean de Spring para fazer isso.
3.1. QuartzoTriggerBuilder
TriggerBuilder é uma API de estilo construtor para construir a entidadeTrigger:
@Bean
public Trigger trigger(JobDetail job) {
return TriggerBuilder.newTrigger().forJob(job)
.withIdentity("Qrtz_Trigger")
.withDescription("Sample trigger")
.withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
.build();
}
3.2. PrimaveraSimpleTriggerFactoryBean
SimpleTriggerFactoryBean fornece o uso do estilo bean para configurarSimpleTrigger. Ele usa o nome do bean Spring como o nome do acionador e o padrão é repetição indefinida, se não especificado de outra forma:
@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setRepeatInterval(3600000);
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
return trigger;
}
4. Configurando oJobStore
JobStore fornece o mecanismo de armazenamento paraJobeTrigger e é responsável por manter todos os dados relevantes para o planejador de job. A API suporta armazenamentosin-memory epersistent.
4.1. Na memóriaJobStore
Para fins de exemplo, usaremos oRAMJobStore na memória, que oferece desempenho extremamente rápido e configuração simples viaquartz.properties:
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
A desvantagem óbvia deRAMJobStore é que ele évolatile por natureza. Todas as informações de agendamento são perdidas entre os desligamentos. Se as definições e planejamentos de trabalho devem ser mantidos entre desligamentos, o persistenteJDBCJobStore deve ser usado em seu lugar. Para habilitar umJobStore na memória no Spring,, definimos esta propriedade em nossoapplication.properties:
spring.quartz.job-store-type=memory
4.2. JDBCJobStore
Existem dois tipos deJDBCJobStore:JobStoreTXeJobStoreCMT. Ambos fazem o mesmo trabalho de armazenamento de informações de agendamento em um banco de dados.
A diferença entre os dois é como eles gerenciam as transações que confirmam os dados. O tipoJobStoreCMT requer uma transação do aplicativo para armazenar dados, enquanto o tipoJobStoreTX inicia e gerencia suas próprias transações.
Existem várias propriedades para definir para umJDBCJobStore. No mínimo, devemos especificar o tipo deJDBCJobStore, a fonte de dados e a classe do driver do banco de dados. Existem classes de driver para a maioria dos bancos de dados, masStdJDBCDelegate cobre a maioria dos casos:
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource
A configuração de um JDBCJobStore no Spring requer algumas etapas. Em primeiro lugar, definimos o tipo de loja em nossoapplication.properties:
spring.quartz.job-store-type=jdbc
Em seguida, precisamos ativar a configuração automática e fornecer ao Spring a fonte de dados necessária ao agendador do Quartz. A anotação@QuartzDataSource faz o trabalho difícil de configurar e inicializar o banco de dados Quartz para nós:
@Configuration
@EnableAutoConfiguration
public class SpringQrtzScheduler {
@Bean
@QuartzDataSource
public DataSource quartzDataSource() {
return DataSourceBuilder.create().build();
}
}
5. Scheduler
A interfaceScheduler é a API principal para fazer a interface com o planejador de trabalho.
UmScheduler pode ser instanciado com umSchedulerFactory. Depois de criado,Jobs eTriggers podem ser registrados nele. Inicialmente, oScheduler está no modo “stand-by” e seu métodostart deve ser invocado para iniciar os threads que acionam a execução de jobs.
5.1. QuartzoStdSchedulerFactory
Simplesmente invocando o métodogetScheduler emStdSchedulerFactory, podemos instanciar oScheduler, inicializá-lo (comJobStoreeThreadPool configurados) e retornar um lidar com sua API:
@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory)
throws SchedulerException {
Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(job, trigger);
scheduler.start();
return scheduler;
}
5.2. PrimaveraSchedulerFactoryBean
SchedulerFactoryBean do Spring fornece o uso do estilo bean para configurar umScheduler, gerencia seu ciclo de vida dentro do contexto do aplicativo e expõe oScheduler como um bean para injeção de dependência:
@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));
schedulerFactory.setJobFactory(springBeanJobFactory());
schedulerFactory.setJobDetails(job);
schedulerFactory.setTriggers(trigger);
schedulerFactory.setDataSource(quartzDataSource);
return schedulerFactory;
}
5.3. ConfigurandoSpringBeanJobFactory
OSpringBeanJobFactory fornece suporte para injetar o contexto do planejador, mapa de dados do trabalho e entradas de dados do gatilho como propriedades no bean de trabalho durante a criação de uma instância.
No entanto, ele carece de suporte para a injeção de referências de bean deapplication context. Graças ao autor dethis blog post, podemos adicionar suporteauto-wiring aSpringBeanJobFactory assim:
@Bean
public SpringBeanJobFactory springBeanJobFactory() {
AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
6. Conclusão
Isso é tudo. Acabamos de construir nosso primeiro planejador básico usando a API Quartz, bem como as classes de conveniência do Spring.
A principal dica deste tutorial é que conseguimos configurar um trabalho com apenas algumas linhas de código e sem usar nenhuma configuração baseada em XML.
Osource code completo para o exemplo está disponível emthis github project. É um projeto Maven que pode ser importado e executado como está. A configuração padrão usa as classes de conveniência do Spring, que podem ser facilmente trocadas para a API Quartz com um parâmetro de tempo de execução (consulte o README.md no repositório).