Parece que estou finalmente chegando ao fim desta série de artigos sobre Rastreamento de Erros usando o Spring e, para quem ainda não leu nenhum texto da série, estou escrevendo um aplicativo Spring simples, mas de qualidade quase corporativa que verifica exceções em arquivos de log e depois gera um relatório. Desde o primeiro artigo da série, estes eram meus requisitos iniciais:
- Busque um determinado diretório e (possivelmente) seus subdiretórios à procura de arquivos de um determinado tipo.
- Se um arquivo for encontrado, verifique sua data: precisa ser feita uma busca de erros?
- Se o arquivo é recente o suficiente para ser verificado, valide-o para buscar exceções.
- Caso contenham exceções, são elas que estamos procurando ou já foram excluídas?
- Se o arquivo contém o tipo de exceção que estamos procurando, adicione os detalhes a um relatório.
- Quando todos os arquivos tiverem sido verificados, formate o relatório que está pronto para ser publicado.
- Publique o relatório usando e-mail ou outra técnica.
- Tudo será executado em uma determinada hora, todos os dias.
Este artigo dá detalhes sobre como cumprir o requisito número 8: “Tudo será executado em uma determinada hora, todos os dias”, e isso significa implementar algum tipo de agendamento.
O Java está aí por um período que já nos dá a impressão de ser longo, o que significa que há várias maneiras de agendar uma tarefa. Estas vão desde:
- Usar uma thread simples com um longo sleep(…).
- Usar objetos Timer e TimerTask.
- Usar ScheduledExecutorService.
- Usar as classes TaskExecutor e TaskScheduler do Spring.
- Usar as anotações @EnableScheduling e @Scheduled do Spring (Spring 3.1 em diante).
- Usar um agendador mais profissional.
Os tipos mais profissionais de agendadores variam do Quartz (gratuito) ao Obsidian (aparentemente muito mais avançado, mas pago). O Spring, como esperado, inclui suporte para Quartz Scheduler. Na verdade, há duas maneiras de integrar o Quartz Scheduler a seu app Spring, e estas são:
1. Usar um JobDetailBean
2. Usar um MethodInvokingJobDetailFactoryBean
Para este aplicativo, estou usando a integração com o Quartz do Spring junto com um MethodInvokingJobDetailFactoryBean. O motivo é que o uso do Quartz me permite configurar minha agenda usando uma expressão cron, e o MethodInvokingJobDetailFactoryBean pode ser configurado rápida e simplesmente usando algumas linhas de XML.
A técnica de expressão cron usada por Spring e Quartz foi descaradamente tirada do agendador cron do Unix. Para obter mais informações sobre como o Quartz lida com expressões de cron, dê uma olhada na página cron Quartz. Se precisar de ajuda para criar suas próprias expressões cron, você vai ver que aquele Cron Maker é um utilitário que ajuda muito.
A primeira coisa a fazer ao configurar Spring e Quartz é incluir as seguintes dependências para seu arquivo de projeto POM:
<!-- QuartzJobBean is in spring-context-support.jar --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework-version}</version> <exclusions> <!-- Exclude Commons Logging in favour of SLF4j --> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- Spring + Quartz need transactions --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework-version}</version> </dependency> <!-- Quartz framework --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>1.8.6</version> <!-- You can't use Quartz two with Spring 3 --> </dependency>
Isso acontece de forma razoavelmente direta com uma minúscula pegadinha no final. Em primeiro lugar, o Quartz do Spring está localizado em spring-context-support-3.2.7.RELEASE.jar (substitua o número da sua versão do Spring se for o caso). Em segundo lugar, você também precisa incluir a biblioteca de transação do Spring – spring-td-3.2.7.RELEASE.jar. Por último, inclua uma versão do agendador Quartz; tenha cuidado, porém, pois o Spring 3.x e o Quartz 2.x não trabalham juntos “fora da caixa” (mas se você procurar por aí pode encontrar correções ad-hoc). Usei a versão 1.8.6 do Quartz, que faz exatamente o que eu preciso que ele faça.
O próximo passo é escolher a configuração XML, e isso envolve três etapas:
- Crie uma instância de MethodInvokingJobDetailFactoryBean. Ela tem duas propriedades: o nome do bean que você deseja chamar em um intervalo agendado e o nome do método nesse bean.
- Conecte o MethodInvokingJobDetailFactoryBean a uma expressão cron usando um CronTriggerFactoryBean.
- Por último, agende esse troço todo usando um SchedulerFactoryBean.
Depois de configurar estes três beans, você recebe um XML que é mais ou menos assim:
<bean id="FileLocatorJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="errorTrackService" /> <property name="targetMethod" value="trackErrors" /> </bean> <bean id="FileLocatorTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="FileLocatorJob" /> <!-- run every morning at 2 AM --> <property name="cronExpression" value="${cron.expression}" /> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="FileLocatorTrigger" /> <!-- Add other triggers for other jobs (if any) here <ref bean="" /> --> </list> </property> </bean>
Note que reservei um lugar para minha expressão cron. A expressão cron real pode ser encontrada no arquivo app.properties:
# run every morning at 2 AM cron.expression=0 0 2 * * ? # Use this to test the app (every minute) #cron.expression=0 0/1 * * * ?
Aqui eu tenho duas expressões: uma que agenda o trabalho para ser executado todos os dias às 2h da manhã e outra, sobre a qual comentei, que executa o trabalho a cada minuto. Essa instância do aplicativo não tem força exatamente industrial. Se houvesse um app “adequado”, eu provavelmente usaria um conjunto diferente de propriedades em cada ambiente (DEV, UAT e produção etc.).
Há apenas algumas etapas a serem cumpridas antes que este app esteja pronto para ser lançado, e a primeira é criar um arquivo JAR executável. Vou falar mais disso na próxima.
O código para este artigo está disponível no GitHub. Se quiser ver outros artigos desta série, dê uma olhada aqui:
- Rastreamento de exceções em aplicativos com o Spring – Parte 01
- Rastreamento de exceções em aplicativos com o Spring: padrão de busca – Parte 02
- Rastreamento de exceções em aplicativos com o Spring: estratégia e pacote privado – Parte 03
- Rastreamento de Exceções: envio de e-mail do Spring – Part 04
***
Artigo traduzido pela Redação iMasters com autorização do autor. Publicado originalmente em http://www.captaindebug.com/2014/04/tracking-exceptions-part-5-scheduling.html