O framework Spring nos permite criar e publicar eventos. Vamos criar uma classe para guardamos os dados do evento:
public class EventoCustomizado extends ApplicationEvent {
private String mensagem;
public EventoCustomizado(Object origem, String mensagem) {
super(origem);
this.mensagem = mensagem;
}
public String getMessagem() {
return messagem;
}
}
a extensão de ApplicationEvent é opcional a partir da versão 4.2.
Publicação de eventos
@Component
public class PublicadorDeEventoCustomizado {
@Autowired
private ApplicationEventPublisher publicadorEventoDaAplicacao;
public void publicarEventoCustomizado(final String mensagem) {
System.out.println("Publicando evento customizado.");
EventoCustomizado eventoCustomizado = new EventoCustomizado(this, mensagem);
publicadorEventoDaAplicacao.publishEvent(eventoCustomizado);
}
}
Ouvintes
Após publicar, um ou mais ouvintes podem receber o evento. O ouvinte deve ser um bean e o método implementado anotado com @EventListener. O ouvinte tem o parâmetro do tipo do evento que irá consumir.
@Component
public class OuvinteEventoCustomizado {
@EventListener
public void iniciarTarefa(EventoCustomizado eventoCustomizado) {
System.out.println("Iniciando processamento da tarefa para o evento customizado.");
}
}
O padrão é definido como síncrono, o publicador é bloqueado até que todos os ouvintes finalizem o processamento do evento.
Eventos assíncronos
Nos eventos assíncronos podem ser iniciados criando um bean ApplicationEventMulticaster com um executor:
@Bean
public ApplicationEventMulticaster multicasterEventoDaAplicacao(DBConfiguration db) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(Executors.newFixedThreadPool(db.getMaxActive() - 1));
return multicaster;
}
As implementações: evento, publicador e ouvinte permanecem as mesmas de antes, mas agora o ouvinte lidará de forma assíncrona com o evento em um encadeamento separado. O método do ouvinte pode ser anotado com @Async.
Eventos vinculados à transação
e por fim eventos que estão vinculados a uma transação:
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void iniciarTarefa(EventoCustomizado eventoCustomizado) {
System.out.println("Iniciando uma tarefa antes da confirmação da transação.");
}
Este ouvinte será chamado somente se houver uma transação na qual o publicador de eventos esteja sendo executado e prestes à realizar uma confirmação da transação. Existe diversos fases que podem ser implementadas.
É possível vincular as seguintes fases da transação:
- AFTER_COMMIT (padrão): é usado para disparar a tarefa relacioanda ao evento, se a transação foi concluída com sucesso.
- AFTER_ROLLBACK: se a transação foi revertida.
- AFTER_COMPLETION: se a transação foi concluída (um alias para AFTER_COMMIT e AFTER_ROLLBACK).
- BEFORE_COMMIT: é usado para disparar a tarefa relacionada ao evento, antes da confirmação da transação. E se nenhuma transação estiver em execução, o evento não será enviado, a menos que seja definindo o atributo fallbackExecution como true.
Conclusões
Os eventos podem ser úteis em diversas soluções de problemas, desde tarefas simples até processamentos que envolvam banco de dados.