
Bonjour à tous! Ce livre est principalement destiné aux développeurs de machines Java et JVM qui recherchent des moyens de créer de meilleurs logiciels en peu de temps en utilisant Spring Boot, Spring Cloud et Cloud Foundry. C'est pour ceux qui ont déjà entendu le bruit monter autour des microservices. Vous avez peut-être déjà réalisé quelle hauteur stratosphérique Spring Boot a décollé, et vous êtes surpris que les entreprises utilisent aujourd'hui la plate-forme Cloud Foundry. Si oui, alors ce livre est pour vous.
Extrait. 3. Style de configuration d'application à douze facteurs
Ce chapitre explique comment implémenter la configuration de l'application.
Définissez un certain nombre de termes de vocabulaire. En ce qui concerne la configuration dans Spring, ce que je veux souvent dire, c'est d'introduire diverses implémentations du contexte d'application,
ApplicationContext , dans l'environnement Spring, ce qui aide le conteneur à comprendre comment connecter les composants du bean. Cette configuration peut être représentée sous la forme d'un fichier XML à soumettre à
ClassPathXmlApplicationContext ou à des classes Java annotées d'une manière qui vous permet d'être fourni à l'objet
AnnotationConfigApplicationContext . Et bien sûr, lorsque nous étudierons la dernière option, nous ferons référence à
la configuration Java.Mais dans ce chapitre, nous allons examiner la configuration sous la forme dans laquelle elle est définie dans le manifeste de l'
application à 12 facteurs . Dans ce cas, il s'agit de valeurs littérales qui peuvent changer d'un environnement à un autre: nous parlons de mots de passe, de ports et de noms d'hôtes, ou d'indicateurs de propriété. La configuration ignore les constantes magiques intégrées au code. Le manifeste comprend un excellent critère pour la configuration correcte: la base de code de l'application peut-elle être open source à tout moment sans divulguer et compromettre les informations d'identification importantes? Ce type de configuration fait exclusivement référence aux valeurs qui varient d'un environnement à l'autre et ne s'appliquent pas, par exemple, à la connexion des beans Spring ou à la configuration des routes Ruby.
Support dans le cadre Spring
Au printemps, un style de configuration à 12 facteurs est pris en charge depuis l'avènement de la classe
PropertyPlaceholderConfigurer . Une fois son instance définie, il remplace les littéraux de la configuration XML par les valeurs extraites du fichier avec l'extension .properties. Dans l'environnement Spring, la classe
PropertyPlaceholderConfigurer est proposée depuis 2003. Spring 2.5 a introduit la prise en charge de l'espace de noms XML et en même temps la prise en charge de la substitution de propriétés dans cet espace. Cela permet la substitution dans la configuration XML des valeurs littérales des définitions des composants du bean par les valeurs affectées aux clés dans le fichier de propriétés externes (dans ce cas, dans le fichier simple.properties, qui peut apparaître dans le chemin d'accès aux classes ou être externe à l'application).
La configuration dans le style de 12 facteurs vise à éliminer le manque de fiabilité des lignes magiques existantes, c'est-à-dire des valeurs comme les adresses des bases de données et les comptes pour s'y connecter, les ports, etc., codés en dur dans une application compilée. Si la configuration est déplacée en dehors de l'application, elle peut être remplacée sans recourir à un nouvel assemblage de code.
Classe PropertyPlaceholderConfigurer
Examinons un exemple d'utilisation de la classe PropertyPlaceholderConfigurer, les définitions XML des composants du bean Spring et un fichier avec l'extension .properties prise hors des limites de l'application. Il suffit d'imprimer la valeur disponible dans ce fichier de propriétés. Cela vous aidera à faire le code montré dans l'exemple 3.1.
Exemple 3.1 Fichier de propriétés: some.properties
configuration.projectName=Spring Framework
Il s'agit de la classe ClassPathXmlApplicationContext de Spring, nous utilisons donc l'espace de noms XML du contexte Spring et pointons vers notre fichier some.properties. Ensuite, nous utilisons des littéraux sous la forme de $ {configuration.projectName} dans les définitions des composants du bean, et Spring les remplacera par les valeurs de notre fichier de propriétés lors de l'exécution (exemple 3.2).
Exemple 3.2. Fichier XML de configuration Spring
<context:property-placeholder location="classpath:some.properties"/> (1) <bean class="classic.Application"> <property name="configurationProjectName" value="${configuration.projectName}"/> </bean>
(1) classpath: un emplacement qui fait référence à un fichier dans le bloc de code compilé actuel (.jar, .war, etc.). Spring prend en charge de nombreuses alternatives, notamment file: et url :, qui permettent au fichier d'exister en dehors du bloc de code.
Enfin, regardons à quoi ressemble la classe Java, grâce à laquelle il est possible de rassembler tout cela (exemple 3.3).
Exemple 3.3 La classe Java qui doit être configurée avec la valeur de propriété
paquet classique;
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); } }
Le premier exemple utilise le format XML de configuration du bean Spring. Dans Spring 3.0 et 3.1, la situation des développeurs utilisant la configuration Java s'est considérablement améliorée. L'annotation de
valeur et l'abstraction d'environnement ont été introduites dans ces versions.
Environnement abstrait et valeur
L'abstraction d'
environnement représente, lors de l'exécution du code, sa relation indirecte avec l'environnement dans lequel il s'exécute, et permet à l'application de poser la question («Quel séparateur de ligne est line.separator sur cette plateforme?») A propos des propriétés de l'environnement. Une abstraction agit comme un mappage à partir de clés et de valeurs. En configurant le PropertySource dans l'environnement, vous pouvez configurer d'où ces valeurs seront lues. Par défaut, Spring charge les clés système et les valeurs d'environnement, telles que line.separator. Vous pouvez demander à Spring de charger les clés de configuration à partir d'un fichier dans le même ordre que celui utilisé dans les versions antérieures de la solution de substitution de propriétés de Spring à l'aide de l'annotation @PropertySource.
L'annotation
Value fournit un moyen d'incorporer des valeurs d'environnement dans les constructeurs, les setters, les champs, etc. Ces valeurs peuvent être calculées à l'aide du Spring Expression Language ou de la syntaxe de substitution de propriété à condition que
PropertySourcesPlaceholderConfigurer soit enregistré, comme dans l'exemple 3.4.
Exemple 3.4. Enregistrer PropertySourcesPlaceholderConfigurer
package 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) Annotation @PropertySource est un raccourci similaire à property-placeholder, qui configure un PropertySource à partir d'un fichier avec l'extension .properties.
(2) PropertySourcesPlaceholderConfigurer doit être enregistré en tant que bean statique, car il s'agit d'une implémentation de BeanFactoryPostProcessor et doit être appelé à un stade précoce du cycle de vie d'initialisation dans le bean Spring. Lorsque vous utilisez des composants de bean dans une configuration Spring XML, cette nuance n'est pas visible.
(3) Vous pouvez décorer les champs avec l'annotation
Value (mais ne le faites pas, sinon le code ne passera pas le test!) ...
(4) ... ou l'annotation
Value peut décorer les paramètres du constructeur ...
(5) ... ou utilisez des méthodes d'installation ...
(6) ... ou intégrez un objet Spring Environment et effectuez la résolution des clés manuellement.
(7) Les paramètres avec l'annotation
Value peuvent également être utilisés dans le fournisseur d'arguments de la méthode
Bean dans la configuration Spring Java.
Dans cet exemple, les valeurs sont chargées à partir du fichier simple.properties, puis il a la valeur configuration.projectName, qui est fournie de différentes manières.
Profils
Entre autres, l'abstraction Environnement introduit des
profils . Cela vous permet d'attribuer des étiquettes (profils) afin de regrouper les composants du bean. Les profils doivent être utilisés pour décrire les composants du bean et les graphiques de bean qui varient d'un environnement à l'autre. Plusieurs profils peuvent être activés simultanément. Les beans auxquels aucun profil n'est affecté sont toujours activés. Les beans qui ont un profil par défaut ne sont activés que s'ils n'ont pas d'autres profils actifs. L'attribut profile peut être spécifié dans la définition du composant bean en XML ou dans les classes de balises, les classes de configuration, les composants bean individuels ou dans les méthodes du fournisseur
Bean utilisant
Profile .
Les profils vous permettent de décrire des ensembles de composants de bean qui doivent être créés dans un environnement quelque peu différemment que dans un autre. Dans un profil de développement local, par exemple, vous pouvez utiliser la source de données H2 intégrée javax.sql.DataSource, puis, lorsque le profil prod est actif, basculez vers la source de données javax.sql.DataSource obtenue à l'aide de la recherche JNDI ou en lisant les propriétés d'une variable d'environnement dans
Cloud Foundry . Dans les deux cas, votre code fonctionnera: vous obtenez javax.sql.DataSource, mais la décision concernant l'instance particulière à utiliser est prise en activant un ou plusieurs profils (exemple 3.5).
Exemple 3.5 Démonstration que les classes @Configuration peuvent charger divers fichiers de configuration et fournir différents beans en fonction de
profil actif
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) Cette classe de configuration et toutes les définitions de
bean qu'elle contient ne seront calculées que si le profil prod est actif.
(2) Cette classe de configuration et toutes les définitions de
bean qu'elle contient ne seront calculées que si le profil de développement est actif ou qu'aucun profil n'est actif, y compris le développement.
(3) Ce composant InitializingBean enregistre simplement le profil actuellement actif et saisit la valeur qui a finalement été entrée dans le fichier de propriétés.
(4) L'activation d'un ou plusieurs profils par programmation est assez simple.
Spring répond à plusieurs autres méthodes d'activation de profil à l'aide du jeton spring_profiles_active ou spring.profiles.active. Un profil peut être défini à l'aide d'une variable d'environnement (par exemple, SPRING_PROFILES_ACTIVE), une propriété JVM (‑Dspring.profiles.active = ...), un paramètre d'initialisation d'application de servlet ou par programme.
Configuration bootiful
Spring Boot améliore considérablement la situation. L'environnement charge initialement automatiquement les propriétés à partir d'une hiérarchie d'emplacements prédéfinis. Les arguments de ligne de commande remplacent les valeurs de propriété dérivées de JNDI, qui remplacent les propriétés obtenues à partir de System.getProperties (), etc.
- Arguments de ligne de commande.
- Attributs JNDI de java: comp / env.
- Propriétés de System.getProperties ().
- Variables d'environnement du système d'exploitation.
- Fichiers de propriétés externes dans le système de fichiers: (config /)? Application. (Yml.properties).
- Fichiers de propriétés internes dans l'archive (config /)? Application. (Yml.properties).
- Annotation @PropertySource dans les classes de configuration.
- Propriétés source de SpringApplication.getDefaultProperties ().
Si le
profil est actif, les données des fichiers de configuration basés sur le nom du profil seront automatiquement lues, par exemple, à partir d'un fichier tel que src / main / resources / application-foo.properties, où foo est le profil actuel.
Si la bibliothèque
SnakeYAML est mentionnée dans les
chemins de classe , les fichiers YAML seront également chargés automatiquement, suivant essentiellement la même convention.
La page de spécification YAML indique que «YAML est une norme lisible par l'homme pour la sérialisation des données pour tous les langages de programmation». YAML est une représentation hiérarchique des valeurs. Dans les fichiers normaux avec l'extension .properties, la hiérarchie est indiquée par un point («.»), Et dans les fichiers YAML, une nouvelle ligne et un niveau de retrait supplémentaire sont utilisés. Il serait intéressant d'utiliser ces fichiers pour éviter d'avoir à spécifier des racines communes en présence d'arbres de configuration hautement ramifiés.
Le contenu d'un fichier avec l'extension .yml est illustré dans l'exemple 3.6.
Exemple 3.6 Fichier de propriétés Application.yml. Les données sont présentées par ordre hiérarchique.
configuration: projectName : Spring Boot management: security: enabled: false
De plus, l'environnement Spring Boot permet d'obtenir beaucoup plus facilement le bon résultat dans les cas généraux. Il transforme les arguments -D en variables d'environnement de processus et java disponibles en tant que propriétés. Il effectue même leur normalisation, dans laquelle la variable d'environnement $ CONFIGURATION_PROJECTNAME (PROJECT_NAME CONFIGURATION) ou l'argument -D sous la forme –Dconfiguration.projectName (configuration.project_name) sont rendus disponibles en utilisant la clé configuration.projectName (configuration.project_name) comme avant. le jeton spring_profiles_active est disponible.
Les valeurs de configuration sont des chaînes et si elles sont suffisantes, elles peuvent devenir illisibles lorsque vous essayez de vous assurer que ces clés ne deviennent pas elles-mêmes des chaînes magiques dans le code. Spring Boot présente le type de composant @ConfigurationProperties. Lors de l'annotation d'un POJO - Plain Old Java Object - à l'aide de @ConfigurationProperties et en spécifiant un préfixe, Spring tentera de mapper toutes les propriétés commençant par ce préfixe aux propriétés POJO. Dans l'exemple ci-dessous, la valeur de configuration.projectName sera mappée sur une instance POJO, que tout le code peut ensuite injecter et déréférencer pour lire les valeurs de type sécurisé. Par conséquent, vous n'aurez qu'un mappage de la clé (String) en un seul endroit (exemple 3.7).
Exemple 3.7. Résolution automatique des propriétés depuis src / main / resources / application.yml
démarrage du package;
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) L'annotation @EnableConfigurationProperties indique à Spring de mapper les propriétés aux POJO annotés avec @ConfigurationProperties.
(2) L'annotation @ConfigurationProperties montre à Spring que ce bean doit être utilisé comme racine pour toutes les propriétés à partir de la configuration., Suivi par des jetons qui correspondent aux propriétés de l'objet.
(3) Le champ projectName aura finalement la valeur affectée à la clé de propriété configuration.projectName.
Spring Boot utilise activement le mécanisme @ConfigurationProperties pour donner aux utilisateurs la possibilité de remplacer les composants élémentaires du système. Vous pouvez remarquer que les clés de propriétés vous permettent d'apporter des modifications, par exemple, en ajoutant la dépendance org.springframework.boot: spring-boot-starter-actuator à une application Web Spring Boot, puis en visitant la page
127.0.0.1 : 8080 / configprops.
Les points de terminaison de l'actionneur seront abordés plus en détail au chapitre 13. Ils sont verrouillés et nécessitent un nom d'utilisateur et un mot de passe par défaut. Les mesures de sécurité peuvent être désactivées (mais uniquement pour examiner ces points) en spécifiant management.security.enabled = false dans le fichier application.properties (ou dans application.yml).
Vous obtiendrez une liste des propriétés de configuration prises en charge en fonction des types présentés dans les chemins de classe lors de l'exécution. À mesure que le nombre de types de Spring Boot augmente, des propriétés supplémentaires s'affichent. Ce point de terminaison affichera également les propriétés exportées par vos POJO qui ont l'annotation @ConfigurationProperties.
Configuration enregistrée centralisée à l'aide de Spring Cloud Configuration Server
Jusqu'à présent, tout va bien, mais les choses doivent être encore plus réussies. Nous n'avons toujours pas répondu aux questions concernant les cas d'utilisation courants:
- après les modifications apportées à la configuration de l'application, un redémarrage est nécessaire;
- pas de traçabilité: comment déterminer les modifications mises en service et si besoin les annuler?
- la configuration est décentralisée; on ne sait pas immédiatement où les modifications doivent être apportées afin de changer l'un ou l'autre aspect;
- aucune prise en charge d'installation pour l'encodage et le décodage à des fins de sécurité.
Serveur de configuration Spring Cloud
Le problème de la centralisation de la configuration peut être résolu en enregistrant la configuration dans un répertoire et en y pointant toutes les applications. Vous pouvez également installer le contrôle de version de ce répertoire en utilisant Git ou Subversion. Ensuite, le soutien nécessaire à la vérification et à l'enregistrement sera reçu. Mais les deux dernières exigences ne seront toujours pas remplies, donc quelque chose de plus sophistiqué est nécessaire. Passez au serveur de configuration
Spring Cloud . La plateforme Spring Cloud propose un serveur de configuration et un client pour ce serveur.
Le serveur Spring Cloud Config est une API REST à laquelle nos clients se connecteront pour récupérer leur configuration. Le serveur gère également le référentiel de configuration du contrôle de version. Il est un intermédiaire entre nos clients et le référentiel de configuration, et est donc dans une position favorable pour implémenter des outils de sécurité pour connecter les connexions des clients au service et les connexions du service aux référentiels de configuration avec contrôle de version. Le client Spring Cloud Config fournit aux applications clientes une nouvelle étendue, actualisée, qui vous permet de reconfigurer les composants Spring sans avoir à redémarrer l'application.
Des technologies telles que le serveur Spring Cloud Config jouent un rôle important, mais entraînent des frais supplémentaires. Idéalement, cette responsabilité devrait être transférée à la plateforme et automatisée. Lorsque vous utilisez Cloud Foundry, vous pouvez trouver le service Config Server dans le catalogue de services, dont les actions sont basées sur l'utilisation du serveur Spring Cloud Config.
Prenons un exemple simple. Tout d'abord, configurez le serveur Spring Cloud Config. Un tel service est accessible par plusieurs applications Spring Boot à la fois. Vous devez le faire fonctionner quelque part et d'une manière ou d'une autre. Il ne reste alors qu'à informer l'ensemble de nos services où trouver le service de configuration. Il fonctionne comme une sorte d'intermédiaire pour les clés de configuration et les valeurs qu'il lit à partir du stockage Git sur le réseau ou à partir du disque. Ajoutez la chaîne org.springframework.cloud: spring-cloud-config-server à l'assembly de votre application Spring Boot pour accéder au serveur Spring Cloud Config (exemple 3.8).
Exemple 3.8. Pour incorporer un serveur de configuration dans l'assembly, utilisez l'annotation @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) L'utilisation de l'annotation @EnableConfigServer entraîne l'installation du serveur Spring Cloud Config.
L'exemple 3.9 montre la configuration du service de configuration.
Exemple 3.9. Configuration du serveur de configuration 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) Une indication d'un référentiel Git fonctionnel de nature locale ou accessible sur le réseau (par exemple, sur GitHub (https://github.com/)) et utilisé par le serveur Spring Cloud Config.
Ici, le service de configuration Spring Cloud est chargé de rechercher des fichiers de configuration pour des clients individuels dans le référentiel Git sur GitHub. Nous avons pointé ce référentiel, mais un lien vers n'importe quel URI Git valide ferait l'affaire. Bien sûr, il n'a même pas besoin de postuler au système Git, vous pouvez utiliser Subversion ou même des répertoires non gérés (bien que nous vous déconseillons fortement de le faire). Dans ce cas, l'URI de stockage est codé en dur, mais rien ne l'empêche d'obtenir de l'argument -D, de l'argument ou d'une variable d'environnement.
»Plus d'informations sur le livre sont disponibles sur
le site Web de l'éditeur»
Contenu»
Extrait20% de réduction sur le coupon pour
les fermenteurs
Java -
Java