Entendendo e Utilizando Profiles em aplicações Spring Boot

Alkxyly Samyr
8 min readApr 19, 2021

Este post faz parte do primeiro desafio lançado pela equipe da Algaworks no curso Especialista Spring Rest.

Afinal de contas, é possível tornar a aplicação flexível a depender do ambiente em que ela se encontra?

Neste post, vamos abordar alguns conceitos e implementações que podem te ajudar a compor o seu arsenal para tomar decisões melhores na hora de tornar sua aplicação flexível, seja no ambiente de desenvolvimento ou no ambiente de produção.

Toda arquitetura bem projetada possui separação de ambientes bem definidos e isso torna o restante do desenvolvimento independente dessas definições.

Spring Profiles

Profiles são configurações que podemos definir para um determinado ambiente em tempo de execução. Por que utilizar Profiles em minhas aplicações?

Quantas vezes nós desenvolvedores precisamos configurar a url de configuração do banco de dados, configurar envio de e-mail, como por exemplo não executar o envio para de e-mails reais no ambiente de desenvolvimento e entre outros exemplos que poderia citar aqui. E mais, queremos executar isso a depender do ambiente em que estamos.

São em cenários desse tipo que veremos a importância do Spring Profile. Realizar essas alterações na mão grande além de ser cansativo pode gerar problemas. Mas que problemas são esses?

Um exemplo muito claro é quando o desenvolvedor gera um artefato que irá para o ambiente de produção e ele simplesmente esquece de alterar alguma configuração que somente deveria estar ativa no ambiente de desenvolvimento.

Isso poderá acarretar uma execução não desejada em sua aplicação.

Antes de te mostrar alguns exemplos de como utilizar o Spring Profiles em suas aplicações, vou falar de um carinha chamado application.properties, pois é onde inserimos algumas propriedades de configuração.

O que é o arquivo application.properties?

O application.properties é um arquivo de configuração gerado automaticamente pelo Spring Boot no momento da criação de um projeto. Ele é responsável por conter propriedades que vão auxiliar o seu projeto definindo por exemplo, pool de conexão, propriedades do banco, configurações de serialização e deserialização e entre outras configurações que podem ser encontradas na documentação do Spring Boot aqui. Há e sem contar que você mesmo pode definir as suas próprias propriedades. Viu o quanto este arquivo é essencial? Então vamos lá!

Feito isso, agora vamos contextualizar nosso cenário

Supomos que temos um controlador e que ao receber uma requisição do tipo GET tenha que disparar uma notificação e a depender do ambiente que se encontra deve ser executado de formas diferentes.

O Controller abaixo tem um método notificar e ele representa nossa porta de entrada a partir de uma requisição no endpoint http://localhost:8080/notificar.

Esse Controller apenas executa o método notificar de um service do Spring. A depender do bean gerenciado no momento, ele irá exibir uma mensagem no console.

Logo abaixo do Controller temos a interface Notificacao .

Em seguida vamos criar nossa primeira classe que implementa a interface Notificacao. Essa classe é responsável por notificar somente no ambiente de desenvolvimento.

Vamos anota-la com o @Component para que nossa classe seja gerenciada pelo container do Spring.

Agora, vamos implementar a classe responsável por notificar somente em ambiente de Produção. E seguindo a mesma ideia temos:

Foi criado também a classe NotificarService responsável por injetar uma instância de Notificacao e executar o método notificar. Essa injeção ocorrerá de acordo com o ambiente.

O que irá acontecer se tentarmos rodar nossa aplicação?

Não será possível iniciar nossa aplicação. Mas por qual motivo isso acontece?

Acontece devido ao fato de termos dois componentes gerenciados pelo Spring e que ambos implementam a mesma interface. Quando isso ocorre e não definimos quem tem mais prioridade temos um caso de ambiguidade.

Console do build do projeto

E vamos resolver isso utilizando o Spring Profile. Com ele vamos dizer qual componente tem que ser reconhecido pelo container do Spring ao iniciar a aplicação. E para isso vamos definir os profiles.

A primeira coisa que vamos fazer é anotar nossas classes com @Profile e passando como parâmetro o nome do ambiente. Por exemplo a String desenvolvimento.

E fazemos a mesma coisa para a classe NotificarEmailProducao só que iremos passar como parâmetro a String producao.

Mas, somente isso não é suficiente. Devemos dizer no momento em que a aplicação irá subir, qual é o profile ativo no momento. Existem algumas formas de fazer isso, vejamos.

A primeira forma consiste em dizer no arquivo de propriedades, aquele arquivo que mencionei no inicio do post, o “application.properties”. Abra este arquivo que fica localizado em src/main/resources e insira a seguinte propriedade.

spring.profiles.active=desenvolvimento

Feito isso, estamos configurando o ambiente pelo qual o profile estará ativo e somente as classes anotadas por ela é que serão reconhecidas pelo Spring.

E como podemos ver qual o profile ativo no momento ? Poderemos ver no console a seguinte mensagem.

The follwing profiles are active: desenvolvimento

Console do build do projeto

O mesmo ocorre com as mensagens que foram colocadas tanto no construtor, quanto no método de notificação da classe que implementa a interface.

Console do build do projeto

Repare que a mensagem passada para o construtor da classe NotificarEmailProducao nem foi chamada, ou seja, nesse momento o Spring não reconhece essa classe como um componente gerenciado. Essa classe só passará a ser reconhecida quando o profile ativo no momento for producao. Fique a vontade para realizar esse teste!

Configurando Profiles pelo SpringToolSuite

Localizando a aba Boot Dashboard clique com o botão direito na instância de sua aplicação Spring Boot e localize a opção Open Config.

Configurando Profile na IDE

Em seguida irá abrir a seguinte tela e uma das opções será o Profile, nele você poderá configurar qual o profile ativo no momento. Ao executar perceberá que o notificador chamado será o de produção.

Criando vários arquivos de configuração

Como já vimos, podemos utilizar o Spring Profile a nível de classes e a partir da anotação @Profile definir em qual situação ela pode ou não ser gerenciada pelo Spring em tempo de execução.

Agora imagine que precisamos utilizar arquivos de configuração a depender do ambiente em que estamos. Com Spring Profile será que podemos fazer isso?

Respondendo a pergunta, Sim!

Podemos utilizar o Spring Profile para termos arquivos específicos por ambiente.

Vamos criar mais dois arquivos de configuração, um para o ambiente de desenvolvimento e outro para o ambiente de produção.

Para cada um deles vamos definir uma porta e um host para simular ambientes diferentes, ou seja, no ambiente de desenvolvimento vamos utilizar host de desenvolvimento e no ambiente de produção vamos utilizar outro host.

Vamos aproveitar e criar nossas próprias propriedades.

No arquivo application-desenvolvimento.properties vamos inserir as seguintes propriedades:

E no arquivo application-producao.properties vamos duplicar e mudar o valor dessas propriedades.

Agora temos três arquivos de configuração. No arquivo principal deixamos o que é comum a qualquer ambiente, que pode ser por exemplo uma porta default.

Com essas informações nos arquivos de configuração, o que você acha de criar uma representação a nível de classe? Com a anotação @ConfigurationProperties isso é possível e é também uma boa prática quando temos várias propriedades que pertencem ao mesmo contexto. Então vamos lá!

Vamos criar a classe NotificacaoProperties , ela irá representar a nossa abstração. Adicionamos a anotação @ConfigurationProperties e por parâmetro colocamos os prefixos que inserimos no arquivo de configuração. Em seguida atribuímos uma porta padrão, pois sempre que o profile mudar e não especificarmos essa propriedade, teremos um valor default.

Agora vamos injetar essa classe na nossa camada Service e no método notificar vamos colocar um System.out.println para visualizar o conteúdo dessas variáveis no console.

Ao configurarmos o profile ativo no momento como desenvolvimento no arquivo application.properties e realizando uma requisição do tipo GET em http://localhost:8080/notificar teremos a seguinte mensagem no console.

Agora que sabemos um pouco mais da importância dos Profiles e como implementa-los em nossas aplicações Spring Boot, como faremos para executar isso em um servidor na hora de fazer o deploy da aplicação? E ainda mais, gerar o artefato sem ter disponível uma IDE?

Pois bem, agora vou te ensinar como gerar um artefato e configurar as propriedades via linha de comando.

Alterando propriedades por linha de comando e variáveis de ambiente.

Vamos supor que queremos subir nossa aplicação para produção. A primeira coisa que temos que fazer é gerar o artefato que iremos implantar. Mas como fazemos isso?

Utilizando o comando do maven podemos gerar esse artefato. Abra o terminal e execute este comando no diretório raiz de seu projeto.

Ao executar este comando teremos a seguinte saída do console.

Quando o processo terminar, será gerado um arquivo com a extensão .jar na pasta target do seu projeto.

Com o arquivo .jar em mãos podemos começar a nossa brincadeira com as propriedades que queremos adicionar via linha de comando. Vamos configurar o profile ativo por linha de comando.

Execute o comando abaixo no terminal.

Utilizando o comando acima e passando como parâmetro a propriedade que define o profile ativo no momento, o servidor irá subir e ao executar uma requisição GET em /notificar teremos a seguinte mensagem no console.

A outra forma, que por sinal é a mais indicada para usar em ambientes reais de produção é utilizando variáveis de ambiente, pois não é uma boa prática adicionar informações sensíveis nos arquivos de propriedade do projeto.

No Windows podemos criar uma variável de ambiente da seguinte forma. Abra seu prompt de comando e digite:

Se quisermos validar se a varável foi criada basta exibir no console utilizando o comando

echo %SPRING_PROFILES_ACTIVE%

É uma boa prática criar variáveis de ambiente seguindo esse padrão, em caixa alta e separadas por um underline.

Feito isso, podemos executar o comando sem passar como parâmetro a propriedade que define o profile ativo no momento.

Conclusão

Utilizar o Spring Profile poderá te ajudar a tornar sua aplicação flexível a depender do ambiente. Espero que essa explicação tenha te ajudado a abrir sua mente sobre a importância de manter seus arquivos, classes e propriedades independente de ambiente.

Tudo isso irá facilitar o deploy de sua aplicação e o desenvolvimento do dia a dia, evitando retrabalho ao configurar sua aplicação ao depender do ambiente que você esteja e por consequência minimizando os riscos ao enviar sua aplicação para o ambiente de produção.

--

--