Eventos com Spring

Postado por Rafael Brandão em Jun. 26, 2022

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.

Referências