Em março de 2021, foi lançado o Spring Native na versão Beta e este novo projeto oferece o suporte oficial para compilar aplicativos Spring para imagens nativas com GraalVM. Isso significa um grande avanço para aplicações Java com Spring, pois com o Spring Native será possível obter todas as melhorias que uma imagem nativa trás, como inicialização quase instantânea e menor consumo de memória, o que resulta em grandes benefícios para arquiteturas de microservices que utilizam Spring Boot.
Com o GraalVM Native Image podemos obter códigos binários totalmente compilados e executáveis através do processo de compilação antecipada. Assim, a imagem nativa gerada contém todas as classes, dependências e outros componentes necessários como biblioteca de tempo de execução, gerenciamento de memória para garantir uma execução autônoma. Ao criar a imagem nativa, o construtor analisa estaticamente quais as classes, métodos, dependências serão acessíveis durante a execução da aplicação e com isso, compila antecipadamente o código e gera um executável que terá um tempo de inicialização muito mais rápido e menor consumo de memória, ou seja, o código nativo gerado deve ser suficiente para a execução.
Todos os metadados sobre as classes, as partes da JDK que não estão sendo utilizadas, dependências, bibliotecas não acessadas e até mesmo partes da própria aplicação que não estão em uso serão descartadas e os recursos não serão incluídos se não houver o carregamento.
O Spring Initializr (https://start.spring.io/) já oferece suporte ao Spring Native e ao iniciar uma aplicação utilizando esse novo projeto, ou seja, ao inserir a dependência do Spring Native ao projeto automaticamente será configurado o plugin Maven ou Gradle para o suporte ao nativo. E no arquivo gerado help.md é possível encontrar links para documentação sobre os projetos utilizados na aplicação que podem servir de guia quando necessário e também verificar se as dependências selecionadas tem o suporte e compatibilidade do Spring Native.
Existem duas formas principais para construir uma aplicação Spring Native através de um projeto Spring Boot que pode ser por Buildpacks para gerar um contêiner contendo um executável nativo ou via plugin Maven de imagem nativa do GraalVM para gerar um executável nativo, lembrando que para ambas as maneiras de geração, o Spring Native versão beta 0.9.1 suporta apenas a versão do Spring Boot 2.4.4 (atual), versões anteriores não são compatíveis.
Iniciando um projeto Spring Boot com Spring Native e Spring MVC, podemos visualizar na imagem abaixo o resultado do arquivo pom.xml, o qual insere a versão do Native como 0.9.1, versão beta.
Ao utilizar o Spring Native é necessário inserir o plugin Spring AOT (ahead-of-time) e se estiver sendo utilizado o Spring Initializr para geração da aplicação isso será feito automaticamente, como pode ser visualizado na imagem abaixo.
O Spring AOT, plug-ins Maven e Gradle, permite a transformação antecipada para criar uma configuração nativa com melhor compatibilidade. Essas transformações antecipadas para gerar a imagem nativa podem ser feitas utilizando uma espécie de dedução do modelo de programação e infraestrutura Spring para gerar configuração nativa GraalVM, já no caso em que essas configurações não são deduzidas é utilizado do Native Hint Annotations que são configurações por meio de arquivos estáticos, na maioria das vezes JSON, que são descobertos automaticamente quando localizados no path META-INF/native-image como por exemplo native-image.properties , reflect-config.json , proxy-config.json ou resource-config.json e por último, o caso mais robusto e amplo, que consiste em utilizar das suposições de infraestrutura e modelagem tanto do Spring quanto do GraalVM Native Image para chegar a melhor compatibilidade possível e diminuir ou até evitar configurações nativas extras.
Então, criando uma imagem de contêiner mínima com um executável contendo Spring Native, Spring Boot, Spring MVC, Tomcat, JDK e o próprio aplicativo (mvn spring-boot:build-image), temos como resultado uma inicialização quase que instantânea, como pode ser observado na imagem abaixo.
Alguns outros frameworks Java já possuem esse suporte para trabalhar de forma nativa, como o Quarkus, Micronaut, Helidon e agora o Spring também conta com essa opção tornando o framework ainda mais robusto e preparado para contar com ganho de performance, diminuição de tempo de inicialização e uso de memória ao executar uma aplicação.
O Spring Native pode ser adotado como uma boa opção e utilizado em diversos cenários, principalmente em aplicações serverless e microservices que devido ao baixo consumo de memória resultará em um menor custo de implantação da arquitetura e também aplicações que utilizam containers e Kubernetes.
Mas como nem tudo são flores, optar por utilizar imagem nativa ao mesmo tempo que há grandes vantagens, há também algumas limitações em alguns cenários que devem ser consideradas e levadas em conta dependendo da aplicação, porém este é um tema para discutirmos no próximo post.
Comments