Agendando tarefas com o TimerService do EJB 3.1

Agendando tarefas com o TimerService do EJB 3.1
steppat
steppat

Compartilhe

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.