Abstraindo o gerenciamento de conexões do banco de dados em uma API Rest com Javalin e seus Handlers
Tags: java, javalin, rest
Published: 2021-09-21 00:23:33

# Como os Frameworks abstraem isso?
Quando utilizei o Spring framework pela primeira vez fiquei curioso quando descobri que as classes criadas através dele (Beans) são, por padrão, singleton. Ou seja, a mesma instância de um @Controller por exemplo, é utilizada em toda requisição feita para a url em que ela está mapeada. Minha curiosidade era em saber como ele lidava com o estado dos atributos desses objetos. Em um bean podemos injetar outros objetos como um EntityManager e nesse caso os valores injetados em uma requisição não devem se misturar com os valores de outra. Devem ser Thread-Safe.

Graças a internet consegui encontrar alguém que teve a mesma curiosidade, foi estudar o código-fonte do Spring e escreveu um post sobre que você pode acessar [aqui](http://shengwangi.blogspot.com/2016/01/why-dao-or-respository-bean-can-be-singleton-in-spring.html). O artigo tem o foco na utilização do @Repository, mas o princípio é o mesmo.

Em resumo, o Spring cria um proxy para cada Bean criado (Que pode ser um @Service, @Repository ou qualquer outro tipo) e internamente ele salva as propriedades que devem ser Thread Safe em um objeto ThreadLocal. Normalmente objetos com a anotação @PersistenceContext não devem existir em 2 threads(Requisições) diferentes. Então, quando existir uma propriedade com essa anotação em um fonte, o que acessamos é apenas um proxy que dará acesso ao valor pertencente àquela thread. Dessa forma não ocorrerá a situação de um EntityManager existir em duas requisições simultâneas.

**Um exemplo bem simples da utilização de um ThreadLocal**
{% gist https://gist.github.com/josevjunior/9e9919f07757d12dd4d03677bcbdf69c %}

# O Microframework Javalin
Quando se trata de microframeworks, existem algumas opções que sempre vem a tona como o Vert.x e Spark (Não o Apache Spark). Porém, o microframework que tive contato foi o Javalin, mesmo não sendo o mais completo, possui uma curva de aprendizado muito baixa, é compatível com Kotlin, tem suporte a Websocket e Server Sent Events (SSE), e é extremamente leve.

**Dependências necessárias para utilizá-lo**
{% gist https://gist.github.com/josevjunior/72f33838712862956857d88992319034 %}

**Um simples exemplo esperando uma requisição na porta 7000**
{% gist https://gist.github.com/josevjunior/476dc3dc18dfcfe645de00a00b60c327 %}

## Como o Javalin funciona
Quando se cria um novo servidor com o Javalin, é possível usar os chamados Handlers (Semelhante a um callback, listener, observable, etc) que serão responsáveis por tratar as requisições http. Os Handlers geralmente são interfaces de apenas um método com um paramêtro do tipo Context (que é um facilitador de acesso aos métodos da classe HttpServletRequest e HttpServletResponse. Sim, o javalin utiliza a api do javax.servlet e sua implementação é o Jetty). Abaixo um exemplo de como utilizá-los.

{% gist https://gist.github.com/josevjunior/488f4d71821a9827ac50438f001d35fd %}

{% gist https://gist.github.com/josevjunior/17988bbc6f402954760f3b28adb7120a %}

# O problema com as conexões
Da primeira vez que utilizei o Javalin eu precisava lidar com o operações com banco de dados. Na época eu não optei por nenhuma biblioteca de ORM para facilitar o acesso aos dados ou de injeção de dependência para outros aspectos. O resultado disso foi muito código chato e repetitivo para tratar acesso ao banco e transações como os abaixo:

{% gist https://gist.github.com/josevjunior/09f5d5e94c9450fcf6fca8dbc7297dea %}

A situação era ainda pior quando precisava implementar algo muito extenso e com várias etapas. Como um método depende do resultado do outro, para manter tudo na mesma transação era preciso passar a referência da conexão que está sendo usada. Como no exemplo seguinte:

{% gist https://gist.github.com/josevjunior/caaed4154884a77d04a911e939b08780 %}

## O que poderia ser feito para evitar esse tipo de código?

Depois de entender a premissa de como o Spring trata seus beans em um ambiente multithread, podemos usar as funcionalidades que o próprio Javalin disponibiliza para chegar em um resultado semelhante.

Com o objetivo de usar uma conexão  por thread, podemos abstrair a criação, fechamento e rollbacks das conexões no ciclo de vida das requisições do Javalin. Dessa forma, podemos nos concentrar somente na lógica dos métodos de negócio sem a necessidade de passar a referência para todos os métodos que dependem de outro.

Mas, por onde começar?

Vinculando uma conexão do banco de dados a uma thread (que é criada para cada requisição feito por um client). E para isso vamos utilizar a classe ThreadLocal para nos ajudar.

* Abaixo temos a classe que será responsável por vincular uma conexão a uma thread. Dessa forma não precisamos nos preocupar com thread-safety na camada de acesso a dados.

{% gist https://gist.github.com/josevjunior/2249ce2a4c5d77d1d003cb679056b3aa %}

* Utilizei o hikari CP para o pool de conexões com a base de dados. O arquivo .properties está disponível no repositório do github.

{% gist https://gist.github.com/josevjunior/4cf8ce744b89bbdd7497e909fd1a2ef0 %}

Agora com os handlers que conversam com o ciclo de vida da requisição, é possíveis criar, fechar e desfazer as alterações feitas durante aquela requisição.

1. Um handler para abrir a conexão a cada requisição
{% gist https://gist.github.com/josevjunior/3fee9982991af09a0361e6899d0a6c8c %}

2. Um Handler para commitar e fechar a conexão após cada requisição
{% gist https://gist.github.com/josevjunior/e14c4f28d9dde639324c01576ca33984 %}

3. Um handler que irá fazer rollback na transação caso uma exceção especifica seja lançada. (Poderia ser qualquer tipo de exceção)
{% gist https://gist.github.com/josevjunior/eb058ca44ccc3a4844d87c6b0a8ef263 %}

Para testar tudo isso, vamos fazer um cadastro simples

1. Uma entidade simples
{% gist https://gist.github.com/josevjunior/406a438aa0441bfbd2bb47c4e352ba5e %}

2. Um service para acessar os dados
{% gist https://gist.github.com/josevjunior/27d33865083faf90f22c7b351eaa5517 %}

3. Um controller que chamará o service
{% gist https://gist.github.com/josevjunior/a7e3e6f94a2aba9ad0c76f43668121ae %}

4. Por fim a classe principal que inicializa tudo. Como não precisamos nos preocupar com threads em relação ao acesso a base de dados, os handlers podem usar sempre a mesma instancia do controlador
{% gist https://gist.github.com/josevjunior/9cb654dbffdca6db8062bb157b88b89a %}

# Conclusão

Esse foi apenas uma demonstração de como é possível utilizar apenas o que o Javalin nos dá para resolver o problema relacionado a gerência de transações/conexões. Claro que poderia ser mais sofisticado utilizando um framework de injeção de dependência ou ORM, mas não era o objetivo do artigo. O código pode ser acessado neste [repositório](https://github.com/josevjunior/transactional-javalin).

Referências
* [https://javalin.io/documentation](https://javalin.io/documentation)

* [https://www.baeldung.com/java-threadlocal](https://www.baeldung.com/java-threadlocal)