Utilizando a API Timer do Java
Inicialmente, em uma implementação utilizando as APIs disponíveis em Java, poderíamos fazer uso da classe Timer
:
Timer timer = new Timer();
Em seguida, faríamos uso do método scheduleAtFixedRate()
que espera uma implementação da classe abstrata TimerTask
como primeiro parâmetro e mais dois parâmetros do tipo long
que indicam o início da execução e tempo constante para reexecutar sucessivamente em milisegundos:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override public void run() {
System.out.println("Executando a primeira vez em " +
"1 segundo e as demais a cada 5 segundos!"); }
}, 1000, 5000);
Em outras palavras, neste exemplo estaríamos executando o código, inicialmente, depois de um segundo, e então, todas as vezes após 5 segundos!
Considerando esse exemplo, para que conseguíssemos realizar aquela consulta para o cliente que verifica o fluxo de vendas de um determinado período, como por exemplo, uma hora, faríamos algo como:
public class VerificadorDePegamentos {
private final long SEGUNDO = 1000;
private final long MINUTO = SEGUNDO * 60;
private final long HORA = MINUTO * 60;
public void verificaPorHora() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override public void run() { // Código que realiza a consulta de fluxo de vendas }
}, 0, HORA);
}
}
Em outras palavras, poderíamos criar uma classe responsável em ficar verificando as vendas realizadas a cada uma hora e nos devolveria a resposta que o nosso cliente tanto espera!
Utilizando a annotation @Scheduled
Porém, veja a quantidade de código que tivemos que escrever para que fosse possível realizar essa tarefa! Neste caso, já que estamos utilizando o Spring, será que não tem uma forma mais fácil?
Felizmente, temos a annotation @Scheduled
que já faz todo o papel do Timer
e TimerTask
pra nós! Em outras palavras, faríamos a mesma coisa que fizemos anteriormente da seguinte maneira:
public class VerificadorDePegamentos {
private final long SEGUNDO = 1000;
private final long MINUTO = SEGUNDO * 60;
private final long HORA = MINUTO * 60;
@Scheduled(fixedDelay = HORA)
public void verificaPorHora() {
// Código que realiza a consulta de fluxo de vendas
}
}
Veja que o código diminuiu e muito! Porém, o que está acontecendo agora? No momento em usamos a annotation @Scheduled
indicamos ao Spring que aquele método será agendado.
Além disso, veja que está sendo enviado o parâmetro fixedDelay
, esse parâmetro é equivalente ao último parâmetro do método scheduleAtFixedRate()
da classe Timer
, ou seja, é o tempo fixo que sempre vai ficar rodando!
Também podemos usar outros parâmetros caso for necessário, segue alguns exemplos:
- initialDelay: Configura a espera inicial do agendamento, basicamente ele é equivalente ao primeiro parâmetro do método
scheduleAtFixedRate()
. Ele também recebe valoreslong
indicando os milisegundos. - fixedRate: Configura um período fixo entre o início e fim da execução do agendamento.
Observe que estamos fazendo a mesma coisa que fazíamos antes, porém com um código muito mais simples de ser compreendido!
Configurando o agendamento no Spring
Conhecemos o Spring como um framework que facilita e muito a vida da pessoa desenvolvedora, isto é, com pouca configuração ele é capaz de gerenciar o ciclo de vida dos objetos entre diversas outras coisas…
Porém, para que isso seja possível, pelo menos uma vez, precisamos indicar ao Spring que ele tenha esse tipo de comportamento! Portanto, para rodarmos o agendamento das tarefas com o Spring, será necessário realizar algumas configurações também.
Transformando a classe em Component
A primeira delas é fazer com que a classe que esteja utilizando a @Scheduled
seja gerenciada pelo Spring. A forma mais fácil de fazer isso é basicamente tornando-a um Component
por meio da annotation @Component
:
@Component public class VerificadorDePegamentos {
//Atributos
@Scheduled(fixedDelay = HORA)
public void verificaPorHora() {
// Código que realiza a consulta de fluxo de vendas
}
}
Habilitando o agendamento
Agora que a classe está sendo gerenciada, precisamos apenas informar ao Spring que queremos habilitar o agendamento para ela por meio da annotation @EnableScheduling
:
@Component @EnableScheduling
public class VerificadorDePegamentos {
e//Atributos
@Scheduled(fixedDelay = HORA)
public void verificaPorHora() {
// Código que realiza a consulta de fluxo de vendas
}
}
Pronto, a nossa classe já está configurada! Agora basta apenas reiniciar o seu projeto do Spring Boot que o agendamento rodará!
Lembrando que para realizar um teste mais perceptível utilize a base dos segundos no parâmetro fixedDelay
ou fixedRate
. 😉
Agendamento por um determinado horário do dia
Veja que agora conseguimos solucionar a situação em que o cliente queria ver a quantidade de vendas a cada 1 hora, ou seja, fizemos um agendamento a cada X tempo. Entretanto, se o cliente chegar e falar o seguinte:
“Quero também um relatório que me mostre quantas vendas foram realizadas até a meio dia de todos os dias!”
E agora? Como poderíamos fazer? Bom, uma solução inicial seria fazer com que a nossa task iniciasse às 12:00h, e então, ela tivesse um tempo fixo de 24:00h, certo? Dessa forma, todas as vezes que passe às 24:00h seria a meio dia de cada dia…
Entretanto, veja que esse tipo de solução não é adequada, afinal, teremos algumas complicações dependendo de alguns cenários, por exemplo:
- Aplicação (servidor) reiniciando: O período de 24:00h não seria mais válido.
- Mudança de horário: Dependendo do cambio do horário teríamos 1 hora a mais ou a menos, ou seja, mais um preocupação.
E agora? Será que tem alguma forma de contornar essa situação?
Agendamento com o Cron
Considerando todos esses cenários, o ideal seria fazer uso de algum tipo de recurso que permitisse de fato configurar de uma forma mais específica, os minutos, horas ou até mesmo o dia que o determinado agendamento será executado.
Um dos mecanismos utilizados em sistemas baseados no Unix (como é o caso do Linux), para o agendamento de tarefas de uma forma mais pontual, é o Cron.
Basicamente o Cron é um programa que permite realizarmos a execução de jobs em um determinado período, como por exemplo: a cada A segundos, B minutos, C horas no dia D execute uma tarefa!
Todas as definições são feitas por meio de um recurso chamado Cron Expression.
Exemplos do uso do Cron
Abaixo seguem alguns exemplos de execução do Cron utilizando Cron Expression:
- A cada segundo: “` “1”
- Todos os dias que o horário tiver ao menos
01
segundos: “` “1” - A cada hora, baseada no relógio, que esteja com
00
minutos e segundos todos os dias: “` “0 0”Exemplos: 00:00:00, 01:00:00...
Significado de cada campo do Cron
A princípio o Cron pode parecer algo muito bizarro, porém, cada campo possui um significado bem especificado. Abaixo é listado o que cada campo significa junto com seus valores esperados:
A B C D E F
- A: Segundos (0 – 59).
- B: Minutos (0 – 59).
- C: Horas (0 – 23).
- D: Dia (1 – 31).
- E: Mês (1 – 12).
- F: Dia da semana (0 – 6).
Note também que nos exemplos foram usados o *
, esse caracter indica que para o campo específicado qualquer valor será considerado.
Observação: Quando fazemos uso do "/"
concatenando algum valor, indicamos o seguinte: para cada (/
) X (valor numérico) repetição acione, em outras palavras, */1
indica que se qualquer valor do campo segundo mudar será acionado, logo, se fosse */2
, a cada 2 vezes que o campo segundo mudar de valor, será acionado.
Usando o Cron no Scheduled
Tendo conhecimento de todo o poder do Cron nessa pequena demonstração, seria superbacana usar um recurso similar ao Cron no @Scheduled
…
Felizmente podemos também fazer uso dele por meio do parâmetro cron
, ou seja, para executar aquele agendamento que pegaria as vendas todos os dias ao meio dia poderia ser feito da seguinte maneira:
@Component @EnableScheduling
public class VerificadorDePegamentos {
private final long SEGUNDO = 1000;
private final long MINUTO = SEGUNDO * 60;
private final long HORA = MINUTO * 60;
@Scheduled(cron = "0 0 12")
public void verificaPorHora() {
System.out.println(LocalDateTime.now());
// Código que realiza a consulta de fluxo de vendas
}
}
Nessa Cron Expression temos uma execução de todos os dias ao meio dia!
Cuidados ao usar o Cron
Embora o Cron resolva o nosso problema de executar uma tarefa em um período bem específico, existe uma situação que pode ser problemática, que é justamente a Time Zone. Em outras palavras, se o local no qual o seu software estiver hospedado tiver um Time Zone diferente do seu, o horário de meio dia pode ser que não seja igual ao seu!
Dessa forma, o Cron causaria mais problemas do que resolveria… E agora?
Como sempre a gente vê, há sempre aquela flexibilidade em configurações quando usamos o Spring, e com o agendamento de tarefas não seria diferente! Ou seja, podemos também definir sob qual Time Zone a @Scheduled
será executada por meio do parâmetro zone
! Então ficaria da seguinte maneira:
@Component @EnableScheduling
public class VerificadorDePegamentos {
private static final String TIME_ZONE = "America/Sao_Paulo";
// atributos
@Scheduled(cron = "0 0 12 \* \* \*", zone = TIME_ZONE) public void verificaPorHora() {
System.out.println(LocalDateTime.now());
// Código que realiza a consulta de fluxo de vendas
}
}
Veja que agora estou enviando o Time Zone America/Sao_Paulo
que é justamente o Time Zone utilizado aqui em São Paulo – SP, portanto, o agendamento poderá ser executado sem a preocupação de onde o projeto esteja alocado!
Querendo conhecer o Spring? Que tal começar hoje mesmo na Formação de Desenvolvedor Java Web com Spring?
Play no vídeo e aprenda.
Aprenda mais sobre a plataforma Java.
Curso de programação para você
Selecionei os cursos on-line para você se preparar e abrir as portas para as vagas de programação. Conheça cada um dos cursos nos links oficiais abaixo.
🙂
Curso Profissional + Certificado + Acesso Vilatício + Suporte.
Full-Stack Web Java EE
Mais de 900 aulas em PrimeFaces, JSF, Spring, Hibernate, JPA, Ireport, CDI e muitos mais. Se torne Full-Stack Java Web.
Full-Stack Web PHP
Domine as principais tecnologias do mercado e se torne Desenvolvedor Full-Stack PHP, com salários na faixa dos R$ 6.000,00.