Conhecendo a JSR-382: Configuration API 1.0

config

Neste post vamos conhecer um pouco sobre a nova especificação de configuração para Jakarta EE .

Esta especificação define uma maneira fácil e flexível para configuração de aplicações, alem de definir maneira de estender o mecanismo de configuração por meio de um SPI (Service Provider Interface) de modo portátil .

A JSR-382 é baseada na inovação do projeto Eclipse Microprofile Config que é realizado por vários colaboradores, tanto por empresas, comunidades como a SouJava e individuais, como o objetivo de identificar uma solução viável minima para dados de configuração de aplicações e micro serviços com a esperança de padronizar via JCP .

Esta JSR foi submetida por todos os membros da comunidade Eclipse MicroProfile .

Introdução a JSR-382 ( JavaConfig )

A maioria das aplicações precisam ser configuradas com base em um ambiente em execução . Esse podem ser os números de portas, endpoint das extremidade Rest ou recursos inteiros que precisam ser ligados e desligados dependendo da instalação.

Tudo isso deve ser possível sem a necessidade de re-empacotar toda a aplicação a cada mudança, alem de levar em consideração as arquiteturas de microserviços e ambientes de contêiners atuais.

A especificação da APi Configuração ou JavaConfig fornece esse objetivo, agregando a configuração de muitos ConfigSources diferentes e apresentando uma única visão mesclada para o usuário, ou seja uma instancia de Config.

Isso permite um agrupamento padrão de configuração dentro da aplicação, alem de permite substituir os padrões de fora, por exemplo : via uma variável de ambiente, uma propriedade do sistema Java ou por meio de um contêiner como Docker ou Kubernetes .

JavaConfig também permite implementar e registrar fontes de configuração(ConfigSources) próprias de maneira portátil como por exemplo : ler valores de configuração de um banco de dados compartilhado em um cluster de aplicações.

O mecanismo principal do JavaConfig é puramente baseado em String. O Type-Safety é intencionalmente fornecido em cima disso, usando apenas os conversores adequados antes de entregar o valor para o chamador.

A chave de configuração pode usar blocos separados por pontos(.) para evitar conflitos de nome. Isso é semelhante aos nomes dos pacotes em Java :

br.org.soujava.url.site=http://soujava.org.br

aqui o exemplo esta na sintaxe do arquivo de propriedade do Java, o conteúdo real poderia também ser lido de um banco de dados ou outros meios.

aqui uma lista de projetos que inspiram diretamente a criação dessa proposta e atuaram como base para essa API como :

E a abordagem de desses foi mesclada no MicroProfiel-Config e agora serve como ponto de partida para a JSR-382.

Gerando o Build e Criando o Projeto

Atualmente a JavaConfig ainda não tem uma RI (Implementação de Referencia) oficial, conforme pode ser visto na seguinte mensagem de um dos lideres da SPEC Mark Struberg para mim :

giiter

como eu não sei qual é a implementação da IBM e da Red Hat, a gente vai usar o Apache Geronimo Config .

outra coisa é que tanto a JavaConfig quanto o Geronimo-Config ainda não estão disponíveis no Maven Central, então a gente vai gerar esse dois localmente , segue os seguinte passos :

1 — Faça o fork e clone da JavaConfig : https://github.com/eclipse/ConfigJSR e do Geronimo https://github.com/apache/geronimo-config (branch ConfigJSR)

2 — Faça o build da JavaConfig e do Geronimo-Config(branch ConfigJSR) com o seguinte comando :

JavaConfig :

mvn clean install -DskipTests

Geronimo-Config :

git checkout ConfigJSR 
mvn clean install -DskipTests

feito isso crie um novo projeto Maven com as seguintes dependências :

aqui a JsonB é somente para exibir uma saída bonita, não é obrigatório para a SPEC funcionar.

Exemplos de uso de configuração

Uma aplicação pode obter sua configuração via programaticamente por meio do ConfigProvider e no CDI com beans habilitados para serem injetados via @Inject Config , com isso uma aplicação pode acessar seus valores configurados por meio dessa instancia de Config .

Um Config consiste nas informações coletadas dos javax.config.spi.ConfigSource registrados . Esses ConfiSource são classificados de acordo com o seu ordinal. Dessa forma é possível sobrescrever a configuração com menor importância .

Por default, existem 3 ConfigSources padrão :

1 — System.getProperties() (ordinal=400)

2 — System.getenv() (ordinal=300)

3 — todos os arquivos META-INF/javaconfig.properties (ordinal=100, configurado separadamente através de uma propriedade config_ordinal dentro de cada arquivo)

Simples exemplo programatico

para o primeiro exemplo vamos utilizar via programaticamente, para isso criar um arquivo properties com o seguinte nome : javaconfig.properties na pasta src/main/resources/META-INF com o seguinte conteúdo de chave/valor :

org.jug.nome=SouJava-Rio
org.jug.membros.quant=709
org.jug.reuniao.mes=1
org.jug.site.url=https://soujava-rio.github.io/

agora cria uma classe com método main e vamos chamar esse valores :

Aqui para usar a JavaConfig em modo programático, temos que usar a classe ConfigProvider que é o ponto central de acesso a configuração . Isso permite acesso a diferentes configurações (representada por uma instancia de Config) na aplicação em que é usado.

Além disso, internamente o ConfigProvider delega até o ConfigProviderResolver, que contém mais funcionalidades de baixo nivel.

Existem 4 maneiras diferentes de criar uma instância do Config:

1 — Em um componente gerenciado pelo CDI atraves do @Inject para acesso a atual configuração da aplicação.

2 — Pelo método de fabrica ConfigProvider.getConfig() para criar um objeto Config com base no ConfigSource pego automaticamente da aplicação identificada pelo ClassLoader.

3 — Pelo método de fabrica ConfigProvider.getConfig(ClassLoader forClassLoader) , este pode ser usado se uma thread do ClassLoader não representar uma camada correta. ex: se necessitamos de um Config para um EAR compartilhado.

4 — e por meio do método de fabrica ConfigProviderResolver.getConfig.instance().getBuilder() para criar um objeto ConfigBuilder . O mesmo não possui um ConfigSource, mais apenas os conversores padrão incluídos.

O ConfigBuilder, pode ser preenchido manualmente via ConfigBuilder#withSources que por padrão. a instancia de Config não será compartilhada pelo ConfigProvider.

Esse método se destina a ser usado se um IoC ou qualquer outroa fabrica puder ser usada para dar acesso a configuração compatilhada criada manualmente.

a saida é um doc json com o valores vindo do javaconfig.properties:

saida2

agora veremos o mesmo exemplo, porem usando CDI .

Simples exemplo com CDI

para isso, adicione o seguinte arquivo beans.xml na pasta src/main/resources/ com o seguinte conteúdo :

e vamos alterar a nossa classe com o seguinte conteúdo :

aqui a chave da propriedade config (@ConfigProperty) usada para procurar o valor da configuração.

já o valor default é usado se o valor da propriedade não exista. Se o tipo de destino não for uma String um javax.config.spi.Converter apropriado será aplicado. Isso significa que qualquer String de valor padão deve seguir as regras de formatação dos conversores cadastrados.

para executar use a seguinte chamada de classe Main da CDI : org.jboss.weld.environment.se.StartMain, se estiver usando o Eclipse IDE, segue a imagem :

eclipse

a saida é um doc json com o valores vindo do javaconfig.properties:

cdi

Conversor

Para fornecer uma configuração Type Safe, precisamos converter as String configuradas para um formato apropriado, isso a JavaConfig fornecer o um conversor para os seguinte tipos :

  • boolean e Boolean. valores para true (insensitivo a maiúsculas) “true”, “1”, “YES”, “Y”, “ON”. Qualquer outro valor será interpresado como falso.
  • int e Integer
  • long e Long
  • float e Float, o “.” é usado para separar os dígitos fracionários.
  • double e Double, o “.” é usado para separar os dígitos fracionários.
  • URL

Além disso podemos adicionar conversores customizados bastando implementar a interface genérica javax.config.spi.Converter e registrar a sua implementação em um arquivo na pasta /META-INF/services/javax.config.spi.Converter com o nome completo da classe customizada.

ConfigAccessor

A API do ConfigAccessor é destinada a valores de configuração digitados e controle preciso sobre a resolução .

O uso mais simples do ConfigAccessor é a resolução de uma propriedade String, que é equivalente a chamada do Config.getValue(propertityKey, String.class ) conforme o seguinte exemplo :

[code language=”java”]

@Inject
private Config config
String jugNome = config.access(“org.jug.nome”).getValue();

Além disso, o ConfigAccessor também permite um controle muito mais complexo sobre o acesso a valores configurados, como o exemplo extraido da spec :

Bem isso é tudo, espero que os leitores tenham gostado de conhecer um pouco sobre a JSR-382 .

código de exemplo no github — JSR-382-JavaConfig .

Referencias