Agendando tarefas com o TimerService do EJB 3.1

A versão 3 dos Enterprise Java Beans trouxe grandes mudanças e muitas simplificações para o desenvolvedor. O forte uso de anotações e convenções, que deixaram os XMLs complexos opcionais, entrou no JPA como forma padrão de persistência para substituir os burocráticos entity beans e a injeção de dependências melhora o design para não depender de lookups acoplados.
O EJB 3.1 foi um passo na mesma direção. Nessa versão as interfaces locais ficaram opcionais, os EJBs podem ser utilizados dentro de um WAR, o que simplifica o empacotamento (EAR não é mais preciso), e várias outras novidades.
Uma das melhorias do EJB 3.1 está relacionada com o agendamento de tarefas dentro do servidor de aplicação, o que é o foco desse post. Mas, para ser exato, o agendamento já era possível nas versões anteriores do EJB (entrou na versão 2.1 da especificação), mas foi muito aperfeiçoado no EJB 3.1.
Como funcionava com EJB 3.0/2.1
Primeiro era preciso definir o método que era chamado quando o @Timeout de um agendamento ocorria. Para isso podemos usar um Session Bean Stateless:
@Stateless @Remote(Agendador.class) //pode ser @Local também public class AgendadorBean implements Agendador {
@Timeout // no EJB 2.1 implementava a interface javax.ejb.TimedObject public void timeout(Timer timer) { System.out.println("Timeout: " + timer.getInfo()); }
Para agendar a execução desse método, usamos o TimerService
. Com ele podemos definir o agendamento e executar um método anotado com @Timeout
apenas uma vez, ou em intervalos (single-action ou interval-action). O TimerService
pode ser injetado, com EJB3, da seguinte maneira:
@Stateless @Remote(Agendador.class) public class AgendadorBean implements Agendador {
@Resource //no EJB 2.1 era preciso usar ejbContext.getTimerService() private TimerService timerService;
public void agenda() { //definir o agendamento - daqui 10s, cada 20s this.timerService.createTimer(10\*1000L, 20\*1000L, "alguma info"); } }
O método createTimer(..)
é sobrecarregado e possui variações, mas não tem como fazer mais do que definir single-action-timer ou interval-action.
O que melhorou com EJB 3.1
No EJB 3.1 o TimerService ganhou métodos para deixar o agendamento mais preciso, baseado em expressões de calendar. Isso é bem parecido com o que o framework Quartz permite no Java, e as expressões cron:
public void agenda() { // cada segunda e quarta as 8:30 ScheduleExpression expression = new ScheduleExpression(); expression.dayOfWeek("Mon,Wed"); expression.hour("8"); expression.minute("30"); this.timerService.createCalendarTimer(expression); System.out.println("Agendado: " + expression); }
Com essas expressões podemos definir intervalos bem precisos e a mesma definição também pode ser feita de forma declarativa, através da anotação @Schedule
. Com ela nem é necessário usar @Timeout
. O método anotado com @Schedule
é invocado quando o timeout ocorre:
//dentro do session bean @Schedule(dayOfWeek="Mon,Wed", hour="8", minute="30") void agendado() { System.out.println("agendado pela anotacao @Schedule"); }
O servidor de aplicação chama então o agendado()
periodicamente. Importante saber que qualquer timer que definir um intervalo (interval-action-timer) é persistido e será recuperado quando o servidor reiniciar. Mas podemos deixar o agendamento não persistente também:
//dentro do session bean @Schedule(dayOfWeek="Mon,Wed", hour="8", minute="30", persistent=false) void agendado() { System.out.println("agendado pela anotacao @Schedule"); }
ou ser for agendado programaticamente:
ScheduleExpression expression = new ScheduleExpression(); //.. TimerConfig config = new TimerConfig(); config.setPersistent(false); this.timerService.createCalendarTimer(expression, config);
Poderíamos ainda melhorar o exemplo usando @Singleton
e @Startup
, outras novidades do EJB 3.1. Isso pode ser útil se for utilizado o agendamento através do @Schedule
não persistente. E claro, isso é apenas mais uma das facilidades que o container EJB e o servidor de aplicação podem oferecer, todos vistos no treinamento Java EE avançado e Web Services.