Trabalhando com eventos no Spring Boot

Criar eventos é uma forma bem interessante de desacoplar componentes dentro de uma aplicação, hoje em dia usamos várias ferramentas que acabam desacoplando aplicações inteiras que precisam se comunicar de forma assíncrona, mas e quando nós precisamos fazer isso em uma escala menor? Como desacoplamos componentes dentro de uma mesma aplicação?

Bom quando estamos usando um framework poderoso como o Spring temos isso dentro do próprio ecossistema, e não há a necessidade de instalar bibliotecas adicionais.

Nesse tutorial vamos ensinar de uma maneira bem prática, como fazer a implementação de maneira simples.

Implementação

Para essa implementação vamos precisar criar basicamente 3 classes, uma classe que vai servir como nosso evento, uma para publicar o evento e outra que vai ser responsável por escutar os eventos publicados, o bom é que o spring já traz para nós interfaces que nos ajudam com essas implementações.

Evento customizado

Vamos criar um classe que vai representar nosso evento propriamente dito, nela fique a vontade para colocar os atributos e métodos que desejar, assim como nomeá-la da forma que preferir, aqui nós vamos dar o nome de CustomEvent para ficar genérico e teremos apenas um atributo que será uma mensagem do tipo texto mesmo.

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent {

	private String message;

	public CustomEvent(Object source, String message) {
		super(source);
		this.message = message;
	}

	public String getMessage() {
		return message;
	}
	
}
Java

Veja que a implementação é bem simples, só precisamos estender a classe abstrata AppllicationEvent presente no próprio framework, e sobrescrever o construtor padrão.

Criamos o atributo message, para trafegar a informação que desejamos, também criamos um método get para que seja possível recuperar essa informação.

Implementando o listener do evento

Agora que já temos nosso evento precisamos criar o responsável por escultar esse quando o mesmo for publicado, para isso vamos criar uma classe que será anotada com @Component e @EventListener, essas são duas anotações padrões do Spring boot e elas que vão permitir com que o método da nossa classe receba a informação no momento em que ela for publicada.

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class CustomEventListener {

	@EventListener
	public void onMessage(CustomEvent event) {
		System.out.println("Message received: " + event.getMessage());
	}
}
Java

Veja que nomeamos a nossa classe como CustomEventListener, mas lembrando que isso não é obrigatório apenas seguimos um padrão para que outros desenvolvedores que venham a dar manutenção no código saiba associar facilmente a sua funcionalidade.

A implementação dessa classe é simples veja que criarmos um método com a assinatura que recebe o nosso evento, e anotamos ele com @EventListener somente isso faz com que todas as publicações envolvendo nosso evento sejam escutadas por esse método.

Também é necessário anotar a classe com @Component para que o Spring possa registrar esse bean no inicio da aplicação e ficar disponível.

Implementando o publicador de eventos

Essa classe será a responsável por publicar o evento, e sua implementação também é bem simples, bastando apenas usar a implementação da classe ApplicationEventPublisher que o próprio spring boot nos entrega.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class CustomEventPublisher {

	@Autowired
	private ApplicationEventPublisher publisher;
	
	public void publish(String message) {
		CustomEvent event = new CustomEvent(this, message);
		publisher.publishEvent(event);
	}
}
Java

Veja que estamos utilizando uma instancia da ApplicationEventPublisher que está sendo injetada pelo próprio Spring boot, através da anotação @Autowired, se você não conhece as anotações do Spring temos um artigo explicando cada uma das principais anotações.

No método publish estamos recebendo a mensagem, construindo nosso evento, e utilizando o método publishEvent, tão simples quanto isso.

Testando o funcionamento

Para testar o correto funcionamento, se estamos conseguindo enviar e escutar o evento, vamos criar uma outra classe que nada mais é que um controller, para recebermos a informação que queremos repassar para o evento via endpoint.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/event")
public class EventController {

	@Autowired
	private CustomEventPublisher publisher;
	
	@PostMapping
	public void onEvent(@RequestBody String message) {
		publisher.publish(message);
	}
}
Java

Essa implementação é bem simples, e só está servindo para gente conseguir testar o funcionamento de uma forma prática.

Agora para testar de fato levante a aplicação e tente enviar uma requisição post com alguma ferramenta de requisições rest (Ex. Postman, Insominia ou o Curl pelo terminal).

Testando a aplicação utilizando Curl

curl --request POST \
  --url http://localhost:8080/event \
  --header 'Content-Type: text/plain' \
  --data 'Aprendi no Artefato X'
Terminal

Testando a aplicação utilizando Wget

wget --quiet \
  --method POST \
  --header 'Content-Type: text/plain' \
  --body-data 'Aprendi no Artefato X' \
  --output-document \
  - http://localhost:8080/event
Terminal

Conclusão

Como demonstrado o próprio Spring já nos entrega a maior parte da implementação, ficando a nosso cargo apenas personalizar o que queremos e adequar a ferramenta a nossa regra de negócio.

Essa é uma excelente oportunidade para desacoplar a comunicação entre componentes internos da sua aplicação, tornando as responsabilidades segregadas, e facilitando a implementação de testes unitários, assim como a manutenção e a evolução do próprio sistema.

Mauricio Lima
Mauricio Lima

Bacharel em Ciência da Computação, profissional dedicado ao desenvolvimento de software e entusiasta da tecnologia.

Artigos: 65