O livro “Java na nuvem. Bota de Primavera, Nuvem de Primavera, Fundição em Nuvem »

imagem Olá pessoal! Este livro é destinado principalmente a desenvolvedores de máquinas Java e JVM que procuram maneiras de criar software melhor em pouco tempo usando o Spring Boot, o Spring Cloud e o Cloud Foundry. É para aqueles que já ouviram o ruído aumentar em torno dos microsserviços. Você já deve ter percebido qual altura estratosférica o Spring Boot decolou e está surpreso que as empresas hoje usem a plataforma Cloud Foundry. Nesse caso, este livro é para você.

Trecho. 3. Estilo de configuração de aplicativo de doze fatores


Este capítulo discutirá como implementar a configuração do aplicativo.

Defina vários termos de vocabulário. Quando se trata de configuração no Spring, na maioria das vezes, quero dizer entrar no ambiente do Spring várias implementações do contexto do aplicativo - ApplicationContext , que ajuda o contêiner a entender como conectar os componentes do bean. Essa configuração pode ser representada como um arquivo XML a ser enviado para as classes ClassPathXmlApplicationContext ou Java anotadas de uma maneira que permita que você seja fornecido ao objeto AnnotationConfigApplicationContext . E, claro, ao estudar a última opção, nos referiremos à configuração Java.

Mas neste capítulo, examinaremos a configuração na forma em que ela é definida no manifesto da aplicação de 12 fatores . Nesse caso, trata-se de valores literais que podem mudar de um ambiente para outro: estamos falando sobre senhas, portas e nomes de host ou sobre sinalizadores de propriedade. A configuração ignora as constantes mágicas incorporadas no código. O manifesto inclui um excelente critério para a configuração correta: a base de código do aplicativo pode ser de código aberto a qualquer momento, sem divulgar e comprometer credenciais importantes? Esse tipo de configuração se refere exclusivamente aos valores que variam de um ambiente para outro e não se aplica, por exemplo, à conexão de beans Spring ou à configuração de rotas Ruby.

Suporte no quadro Spring


No Spring, um estilo de configuração de 12 fatores é suportado desde o advento da classe PropertyPlaceholderConfigurer . Uma vez definida sua instância, ela substitui os literais na configuração XML pelos valores extraídos do arquivo pela extensão .properties. No ambiente Spring, a classe PropertyPlaceholderConfigurer é oferecida desde 2003. O Spring 2.5 introduziu suporte para o espaço para nome XML e, ao mesmo tempo, suporte para substituição de propriedade nesse espaço. Isso permite a substituição na configuração XML dos valores literais das definições dos componentes do bean pelos valores designados às chaves no arquivo de propriedades externas (nesse caso, no arquivo simple.properties, que pode aparecer no caminho da classe ou ser externo ao aplicativo).

A configuração no estilo de 12 fatores visa eliminar a falta de confiabilidade das seqüências mágicas existentes, ou seja, valores como os endereços dos bancos de dados e as contas para conexão com eles, portas, etc., codificados no aplicativo compilado. Se a configuração for movida para fora do aplicativo, poderá ser substituída sem recorrer a um novo conjunto de códigos.

Classe PropertyPlaceholderConfigurer


Vejamos um exemplo de uso da classe PropertyPlaceholderConfigurer, definições XML dos componentes do bean Spring e um arquivo com uma extensão .properties removida dos limites do aplicativo. Apenas precisamos imprimir o valor disponível neste arquivo de propriedades. Isso ajudará a executar o código mostrado no Exemplo 3.1.

Exemplo 3.1 Arquivo de propriedades: some.properties

configuration.projectName=Spring Framework 

Esta é a classe ClassPathXmlApplicationContext do Spring, portanto, usamos o espaço para nome XML no contexto do Spring e apontamos para o arquivo some.properties. Em seguida, usamos literais na forma de $ {configuration.projectName} nas definições dos componentes do bean, e o Spring os substituirá pelos valores do nosso arquivo de propriedades durante a execução (exemplo 3.2).

Exemplo 3.2 Arquivo XML de configuração do Spring

 <context:property-placeholder location="classpath:some.properties"/> (1) <bean class="classic.Application"> <property name="configurationProjectName" value="${configuration.projectName}"/> </bean> 

(1) classpath: local que se refere ao arquivo no atual bloco de código compilado (.jar, .war etc.). O Spring suporta muitas alternativas, incluindo file: e url :, que permitem que o arquivo exista além do bloco de código.

Por fim, vamos ver como é a classe Java, graças à qual é possível reunir tudo isso (Exemplo 3.3).

Exemplo 3.3 A classe Java que deve ser configurada com o valor da propriedade
pacote clássico;

 import org.apache.commons.logging.LogFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Application { public static void main(String[] args) { new ClassPathXmlApplicationContext("classic.xml"); } public void setConfigurationProjectName(String pn) { LogFactory.getLog(getClass()).info("the configuration project name is " + pn); } } 

O primeiro exemplo usa o formato XML de configuração do bean Spring. No Spring 3.0 e 3.1, a situação dos desenvolvedores que usam a configuração Java melhorou significativamente. A anotação Value e a abstração Environment foram introduzidas nesses releases.

Ambiente e valor abstratos


A abstração do ambiente representa, durante a execução do código, sua relação indireta com o ambiente em que está sendo executado e permite que o aplicativo faça a pergunta (“Qual separador de linha é line.separator nesta plataforma?”) Sobre as propriedades do ambiente. Uma abstração atua como um mapeamento de chaves e valores. Ao configurar o PropertySource no ambiente, você pode configurar de onde esses valores serão lidos. Por padrão, o Spring carrega chaves do sistema e valores do ambiente, como line.separator. Você pode instruir o Spring a carregar chaves de configuração de um arquivo na mesma ordem que poderia ser usada em versões anteriores da solução de substituição de propriedades do Spring usando a anotação @PropertySource.

A anotação Value fornece uma maneira de incorporar valores de ambiente em construtores, setters, campos etc. Esses valores podem ser calculados usando o Spring Expression Language ou a sintaxe de substituição de propriedade, desde que o PropertySourcesPlaceholderConfigurer esteja registrado, como no Exemplo 3.4.

Exemplo 3.4 Registrar PropertySourcesPlaceholderConfigurer
pacote env;

 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import javax.annotation.PostConstruct; (1) @Configuration @PropertySource("some.properties") public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) throws Throwable { new AnnotationConfigApplicationContext(Application.class); } (2) @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (3) @Value("${configuration.projectName}") private String fieldValue; (4) @Autowired Application(@Value("${configuration.projectName}") String pn) { log.info("Application constructor: " + pn); } (5) @Value("${configuration.projectName}") void setProjectName(String projectName) { log.info("setProjectName: " + projectName); } (6) @Autowired void setEnvironment(Environment env) { log.info("setEnvironment: " + env.getProperty("configuration.projectName")); } (7) @Bean InitializingBean both(Environment env, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("@Bean with both dependencies (projectName): " + projectName); log.info("@Bean with both dependencies (env): " + env.getProperty("configuration.projectName")); }; } @PostConstruct void afterPropertiesSet() throws Throwable { log.info("fieldValue: " + this.fieldValue); } } 

(1) A anotação @PropertySource é uma abreviação similar ao property-placeholder, que configura um PropertySource a partir de um arquivo com a extensão .properties.

(2) PropertySourcesPlaceholderConfigurer precisa ser registrado como um bean estático, pois é uma implementação do BeanFactoryPostProcessor e deve ser chamado em um estágio inicial do ciclo de vida de inicialização no bean Spring. Ao usar componentes de bean na configuração XML da Spring, essa nuance não é visível.

(3) Você pode decorar os campos com a anotação Valor (mas não faça isso, caso contrário, o código não passará no teste!) ...

(4) ... ou a anotação Value pode decorar os parâmetros do construtor ...

(5) ... ou use métodos de instalação ...

(6) ... ou incorpore um objeto Spring Environment e execute a resolução das teclas manualmente.

(7) Os parâmetros com a anotação Value também podem ser usados ​​no provedor de argumentos do método Bean na configuração Spring Java.

Neste exemplo, os valores são carregados no arquivo simple.properties e, em seguida, ele possui o valor configuration.projectName, que é fornecido de várias maneiras.

Perfis


Entre outras coisas, a abstração do ambiente apresenta perfis . Isso permite atribuir etiquetas (perfis) para agrupar componentes do bean. Os perfis devem ser utilizados para descrever componentes e gráficos de beans que variam de ambiente para ambiente. Vários perfis podem ser ativados simultaneamente. Os beans que não possuem perfis atribuídos a eles são sempre ativados. Os grãos que têm um perfil padrão são ativados apenas se não tiverem outros perfis ativos. O atributo profile pode ser especificado na definição do componente do bean em XML ou nas classes de tags, classes de configuração, componentes individuais do bean ou nos métodos do provedor Bean usando Profile .

Os perfis permitem descrever conjuntos de componentes de bean que devem ser criados em um ambiente de maneira um pouco diferente do que em outro. Em um perfil de desenvolvedor de desenvolvimento local, por exemplo, você pode usar a fonte de dados H2 incorporada javax.sql.DataSource e, quando o perfil do produto estiver ativo, alterne para a fonte de dados javax.sql.DataSource obtida usando a pesquisa JNDI ou lendo propriedades de uma variável de ambiente no Cloud Foundry . Nos dois casos, seu código funcionará: você obtém o javax.sql.DataSource, mas a decisão sobre qual instância específica usar é tomada ativando um perfil ou vários (exemplo 3.5).

Exemplo 3.5 Demonstração de que as classes @Configuration podem carregar vários arquivos de configuração e fornecer beans diferentes com base em
perfil ativo

 package profiles; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @Configuration public class Application { private Log log = LogFactory.getLog(getClass()); @Bean static PropertySourcesPlaceholderConfigurer pspc() { return new PropertySourcesPlaceholderConfigurer(); } (1) @Configuration @Profile("prod") @PropertySource("some-prod.properties") public static class ProdConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("prod InitializingBean"); } } @Configuration @Profile({ "default", "dev" }) (2) @PropertySource("some.properties") public static class DefaultConfiguration { @Bean InitializingBean init() { return () -> LogFactory.getLog(getClass()).info("default InitializingBean"); } } (3) @Bean InitializingBean which(Environment e, @Value("${configuration.projectName}") String projectName) { return () -> { log.info("activeProfiles: '" + StringUtils.arrayToCommaDelimitedString(e.getActiveProfiles()) + "'"); log.info("configuration.projectName: " + projectName); }; } public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(); ac.getEnvironment().setActiveProfiles("dev"); (4) ac.register(Application.class); ac.refresh(); } } 

(1) Esta classe de configuração e todas as definições de Bean contidas nela serão calculadas apenas se o perfil do produto estiver ativo.

(2) Esta classe de configuração e todas as definições de Bean contidas nela serão calculadas apenas se o perfil do desenvolvedor estiver ativo ou se nenhum perfil estiver ativo, incluindo o desenvolvedor.

(3) Esse componente InitializingBean simplesmente registra o perfil ativo no momento e insere o valor que foi inserido no arquivo de propriedades.

(4) A ativação de um perfil (ou perfis) programaticamente é bastante simples.

O Spring responde a vários outros métodos de ativação de perfil usando o token spring_profiles_active ou spring.profiles.active. Um perfil pode ser configurado usando uma variável de ambiente (por exemplo, SPRING_PROFILES_ACTIVE), uma propriedade da JVM (‑Dspring.profiles.active = ...), um parâmetro de inicialização do aplicativo de servlet ou programaticamente.

Configuração Bootiful


Spring Boot melhora significativamente a situação. O ambiente inicialmente carregará propriedades automaticamente de uma hierarquia de locais predefinidos. Os argumentos da linha de comandos substituem os valores de propriedade derivados de JNDI, que substituem as propriedades obtidas de System.getProperties () etc.

- argumentos de linha de comando.
- Atributos JNDI de java: comp / env.
- Propriedades de System.getProperties ().
- Variáveis ​​de ambiente do sistema operacional.
- Arquivos de propriedades externas no sistema de arquivos: (config /)? Application. (Yml.properties).
- Arquivos de propriedades internas no arquivo morto (config /)? Aplicativo. (Yml.properties).
- Anotação @PropertySource nas classes de configuração.
- Propriedades de origem de SpringApplication.getDefaultProperties ().

Se o perfil estiver ativo, os dados dos arquivos de configuração baseados no nome do perfil serão lidos automaticamente, por exemplo, de um arquivo como src / main / resources / application-foo.properties, em que foo é o perfil atual.

Se a biblioteca SnakeYAML for mencionada nos caminhos da classe, os arquivos YAML também serão carregados automaticamente, seguindo basicamente a mesma convenção.

A página de especificação YAML afirma que "YAML é um padrão legível por humanos para serializar dados para todas as linguagens de programação". YAML é uma representação hierárquica de valores. Em arquivos regulares com a extensão .properties, a hierarquia é indicada por um ponto (“.”). Nos arquivos YAML, uma nova linha e um nível de recuo adicional são usados. Seria bom usar esses arquivos para evitar a necessidade de especificar raízes comuns na presença de árvores de configuração altamente ramificadas.

O conteúdo de um arquivo com a extensão .yml é mostrado no Exemplo 3.6.

Exemplo 3.6 Arquivo de propriedades Application.yml. Os dados são apresentados em ordem hierárquica.

 configuration: projectName : Spring Boot management: security: enabled: false 

Além disso, o ambiente Spring Boot facilita muito a obtenção do resultado certo em casos gerais. Ele transforma os argumentos -D em variáveis ​​de ambiente do processo e java disponíveis como propriedades. Ele ainda realiza sua normalização, na qual a variável de ambiente $ CONFIGURATION_PROJECTNAME (PROJECT_NAME CONFIGURATION) ou o argumento -D no formato -Dconfiguration.projectName (configuration.project_name) são disponibilizados usando a chave configuration.projectName (configuration.project_name) como antes. o token spring_profiles_active está disponível.

Os valores de configuração são cadeias e, se forem suficientes, podem se tornar ilegíveis ao tentar garantir que essas chaves não se tornem cadeias mágicas no código. O Spring Boot apresenta o tipo de componente @ConfigurationProperties. Ao anotar um POJO - Objeto Java Antigo Simples - usando @ConfigurationProperties e especificando um prefixo, o Spring tentará mapear todas as propriedades começando com esse prefixo para as propriedades do POJO. No exemplo abaixo, o valor para configuration.projectName será mapeado para uma instância do POJO, na qual todo o código poderá injetar e desreferenciar para ler valores de segurança de tipo. Como resultado, você terá apenas um mapeamento a partir da chave (String) em um único local (Exemplo 3.7).

Exemplo 3.7 Resolução automática de propriedades em src / main / resources / application.yml
inicialização do pacote;

 import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; (1) @EnableConfigurationProperties @SpringBootApplication public class Application { private final Log log = LogFactory.getLog(getClass()); public static void main(String[] args) { SpringApplication.run(Application.class); } @Autowired public Application(ConfigurationProjectProperties cp) { log.info("configurationProjectProperties.projectName = " + cp.getProjectName()); } } (2) @Component @ConfigurationProperties("configuration") class ConfigurationProjectProperties { private String projectName; (3) public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } } 

(1) A anotação @EnableConfigurationProperties diz ao Spring para mapear propriedades para POJOs anotados com @ConfigurationProperties.

(2) A anotação @ConfigurationProperties mostra ao Spring que este bean deve ser usado como raiz para todas as propriedades que começam com a configuração., Seguido por tokens que mapeiam as propriedades do objeto.

(3) O campo projectName terá o valor atribuído à chave de propriedade configuration.projectName.

O Spring Boot usa ativamente o mecanismo @ConfigurationProperties para fornecer aos usuários a capacidade de substituir os componentes elementares do sistema. Você pode observar que as chaves de propriedade permitem fazer alterações, por exemplo, adicionando a dependência org.springframework.boot: spring-boot-starter-actuator a um aplicativo Web baseado no Spring Boot e, em seguida, visitando a página 127.0.0.1 : 8080 / configprops.

Os pontos de extremidade do atuador serão discutidos em mais detalhes no Capítulo 13. Eles estão bloqueados e requerem um nome de usuário e senha padrão. As medidas de segurança podem ser desativadas (mas apenas para examinar esses pontos), especificando management.security.enabled = false no arquivo application.properties (ou em application.yml).

Você obterá uma lista de propriedades de configuração suportadas com base nos tipos apresentados nos caminhos de classe em tempo de execução. À medida que o número de tipos de inicialização Spring aumenta, propriedades adicionais serão mostradas. Esse terminal também exibirá propriedades exportadas pelos seus POJOs que possuem a anotação @ConfigurationProperties.

Configuração registrada centralizada usando o Spring Cloud Configuration Server


Até agora, está tudo bem, mas as coisas precisam ser ainda mais bem-sucedidas. Ainda não respondemos perguntas sobre casos de uso comuns:

  • após as alterações feitas na configuração do aplicativo, é necessária uma reinicialização;
  • sem rastreabilidade: como determinar as alterações colocadas em operação e, se necessário, revertê-las?
  • a configuração é descentralizada; não está claro imediatamente onde as alterações devem ser feitas para alterar um ou outro aspecto;
  • nenhum suporte de instalação para codificação e decodificação por motivos de segurança.

Servidor de configuração do Spring Cloud


O problema de centralizar a configuração pode ser resolvido salvando a configuração em um diretório e apontando todos os aplicativos para ele. Você também pode instalar o controle de versão deste diretório usando o Git ou o Subversion. Em seguida, o suporte necessário para verificação e registro será recebido. Mas os dois últimos requisitos ainda não serão atendidos, portanto, é necessário algo mais sofisticado. Vá para o servidor de configuração do Spring Cloud . A plataforma Spring Cloud oferece um servidor de configuração e um cliente para esse servidor.

O servidor Spring Cloud Config é uma API REST à qual nossos clientes se conectam para recuperar sua configuração. O servidor também gerencia o repositório de configuração de controle de versão. Ele é um intermediário entre nossos clientes e o repositório de configuração e, portanto, está em uma posição favorável para implementar ferramentas de segurança para conectar conexões de clientes ao serviço e conexões do serviço ao repositório de configuração com controle de versão. O cliente Spring Cloud Config fornece aos aplicativos clientes um novo escopo, atualização, que permite configurar os componentes do Spring novamente sem precisar reiniciar o aplicativo.

Tecnologias como o servidor Spring Cloud Config desempenham um papel importante, mas exigem sobrecarga adicional. Idealmente, essa responsabilidade deve ser transferida para a plataforma e automatizada. Ao usar o Cloud Foundry, você pode encontrar o serviço do Servidor de Configuração no catálogo de serviços, cujas ações são baseadas no uso do servidor Spring Cloud Config.

Considere um exemplo simples. Primeiro, configure o servidor Spring Cloud Config. Um desses serviços pode ser acessado por vários aplicativos Spring Boot ao mesmo tempo. Você precisa fazê-lo funcionar em algum lugar e de alguma forma. Resta apenas notificar todos os nossos serviços sobre onde encontrar o serviço de configuração. Ele funciona como um tipo de intermediário para chaves de configuração e valores que ele lê do armazenamento Git na rede ou no disco. Adicione a sequência org.springframework.cloud: spring-cloud-config-server ao assembly do seu aplicativo Spring Boot para entrar no servidor Spring Cloud Config (exemplo 3.8).

Exemplo 3.8 Para incorporar um servidor de configuração no assembly, use a anotação @EnableConfigServer

 package demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; (1) @SpringBootApplication @EnableConfigServer public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

(1) O uso da anotação @EnableConfigServer faz com que o servidor Spring Cloud Config seja instalado.

O Exemplo 3.9 mostra a configuração para o serviço de configuração.

Exemplo 3.9 Configuração do servidor src / main / resources / application.yml

server.port = 8888
spring.cloud.config.server.git.uri = \
github.com/cloud-native-java/config-server-configuration-repository (1)

(1) Uma indicação de um repositório Git em funcionamento, de natureza local ou acessível pela rede (por exemplo, no GitHub (https://github.com/)) e usado pelo servidor Spring Cloud Config.

Aqui, o serviço de configuração do Spring Cloud é instruído a procurar arquivos de configuração para clientes individuais no repositório Git no GitHub. Apontamos para este repositório, mas seria necessário um link para qualquer URI do Git válido. Obviamente, ele nem precisa se inscrever no sistema Git, você pode usar o Subversion ou mesmo diretórios não gerenciados (embora seja altamente recomendável não fazer isso). Nesse caso, o URI de armazenamento é codificado permanentemente, mas não há nada para impedi-lo de obter do argumento -D, do argumento ou de uma variável de ambiente.

»Mais informações sobre o livro podem ser encontradas no site do editor
» Conteúdo
» Trecho

20% de desconto no cupom para Java Fermenters - Java

Source: https://habr.com/ru/post/pt425109/


All Articles