[JAVA] Comment obtenir la valeur du paramètre (valeur de la propriété) à partir de la base de données dans Spring Framework

Lors de la gestion des valeurs de réglage dans Spring Framework, les valeurs de réglage peuvent être spécifiées dans les fichiers de propriétés, les propriétés système (valeurs spécifiées par -D), les variables d'environnement du système d'exploitation, JNDI (environnement d'application Web uniquement), etc. Il peut être obtenu via @ Value ou ʻEnvironment`.

Par exemple, cela ressemble à ce qui suit.

Exemple de spécification de valeur de réglage(fichier de propriétés)


services.user.url=http://user.service.com/{id}
services.company.url=http://company.service.com/{id}

Exemple de référence de valeur de réglage


@Service
public class MyService {

  private final RestTemplate restTemplate = new RestTemplate();
  private final Environment environment;

  @Value("${services.user.url}") //Injectez la valeur de réglage lors de la génération du bean
  private String userServiceUrl;

  public MyService(Environment environment) {
    this.environment = environment;
  }

  public User getUser(String id) {
    User user = restTemplate.getForObject(userServiceUrl, User.class, id);
    return user;
  }

  public Company getCompany(String id) {
    String companyServiceUrl = environment.getProperty("services.company.url"); //Obtenir la valeur définie lors de l'exécution
    Company company = restTemplate.getForObject(companyServiceUrl, User.class);
    return company;
  }

}

Dans Spring Boot, au lieu de "@ Value", "[Propriétés de configuration de type sécurisé](https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#" Je pense qu'il est courant d'utiliser "boot-features-external-config-typesafe-configuration-properties)", mais ici ** intentionnellement ** " @ Value` "est utilisé comme espace réservé de propriété (" Spécifie d'utiliser «$ {...}»). (Bien que je ne l'explique pas, la méthode présentée ici est également applicable aux "Propriétés de configuration de type sécurisé")

Spring Framwork (malheureusement?) Ne fournit pas de classe pour obtenir les paramètres de la base de données, mais la destination de sauvegarde des paramètres est abstraite par une classe appelée PropertySource, donc les paramètres de la base de données. Si vous créez une PropertySource et que vous l'appliquez à ʻEnvironment`, vous pouvez y faire référence depuis votre application.

Créer une PropertySource pour obtenir les paramètres de la base de données

Essayez de créer une classe qui obtient la valeur de paramètre de la base de données au démarrage, la met en cache et met à jour le cache à tout moment (bien que la sécurité des threads semble suspecte ...).

package com.example.demo;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class JdbcPropertySource extends EnumerablePropertySource<DataSource> implements InitializingBean {

  private final JdbcTemplate jdbcTemplate;
  private final String[] tableNames;
  private Map<String, Object> properties = Collections.emptyMap();

  public JdbcPropertySource(String name, DataSource dataSource, String... tableNames) {
    super(name, dataSource);
    this.jdbcTemplate = new JdbcTemplate(dataSource);
    this.tableNames = tableNames.length == 0 ? new String[]{"t_properties"} : tableNames;
  }

  @Override
  public String[] getPropertyNames() {
    return properties.keySet().toArray(new String[0]);
  }

  @Override
  public Object getProperty(String name) {
    Map<String, Object> currentProperties = properties;
    return currentProperties.get(name);
  }

  @Override
  public void afterPropertiesSet() {
    load();
  }

  public void load() {
    Map<String, Object> loadedProperties = Stream.of(tableNames)
        .flatMap(tableName -> jdbcTemplate.queryForList("SELECT name, value FROM " + tableName).stream())
        .collect(Collectors.toMap(e -> (String) e.get("name"), e -> e.get("value")));
    this.properties = loadedProperties;
  }

}

Application à «Environnement»

package com.example.actuatordemo;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;

import javax.sql.DataSource;

@Configuration
public class MyConfiguration {

  //Paramètres DataSource
  @Bean
  DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.H2)
        .setName("demo")
        .addScript("classpath:init-db.sql")
        .build();
  }

  //Paramètre de JdbcPropertySource créé cette fois
  @Bean
  JdbcPropertySource jdbcPropertySource(DataSource dataSource) {
    return new JdbcPropertySource("jdbcProperties", dataSource);
  }

  //Définition de bean pour appliquer le JdbcPropertySource créé cette fois à l'environnement
  @Bean
  static BeanFactoryPostProcessor environmentPropertySourcesCustomizer() {
    return bf -> {
      ConfigurableEnvironment environment = bf.getBean(ConfigurableEnvironment.class);
      JdbcPropertySource propertySource = bf.getBean(JdbcPropertySource.class);
      //Appliquer selon la priorité suivante des variables d'environnement du système d'exploitation (la priorité est déterminée en fonction des exigences)
      environment.getPropertySources()
          .addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, propertySource);
    };
  }

  //Définition de bean pour activer les espaces réservés de propriété
  @Bean
  static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
  }

}

Cette fois, je l'ai appliqué à ʻEnvironment en utilisant le mécanisme de BeanFactoryPostProcessor`. Est-ce la meilleure méthode? N'est pas très confiant. Je vous serais reconnaissant si vous pouviez dire s'il y a une meilleure façon.

Préparer la base de données

Étant donné que cette entrée utilise une base de données intégrée, préparez une table et SQL pour saisir les données.

src/main/resources/init-db.sql


drop table t_properties if exists;
create table t_properties (
  name varchar(512) not null primary key,
  value text
);

insert into t_properties (name, value) values ('services.user.url','http://dev01/services/user/{id}');
insert into t_properties (name, value) values ('services.company.url','http://dev01/services/company/{id}');

Résumé

Dans le cas où je suis actuellement impliqué (cas non-Spring Boot ...), il peut être nécessaire (éventuellement) d'avoir des valeurs de réglage dans la base de données (du point de vue du fonctionnement du système), alors que puis-je faire techniquement? J'y ai pensé et en ai fait un prototype. Il semble y avoir une marge d'amélioration telle que la garantie de la sécurité des threads, mais je suis soulagé de savoir que cela peut être réalisé en utilisant les points d'extension de Spring Framework.

Recommended Posts

Comment obtenir la valeur du paramètre (valeur de la propriété) à partir de la base de données dans Spring Framework
Comment obtenir la date avec Java
Comment obtenir une classe depuis Element en Java
Comment se lier avec un fichier de propriétés dans Spring Boot
[Spring Boot] Comment se référer au fichier de propriétés
Je veux obtenir la valeur en Ruby
Comment créer votre propre annotation en Java et obtenir la valeur
[Spring Boot] Comment obtenir des propriétés dynamiquement à partir d'une chaîne contenue dans une URL
[Java] Comment obtenir la valeur maximale de HashMap
[Android] Comment obtenir la langue de réglage du terminal
[Java] Comment obtenir la clé et la valeur stockées dans Map par traitement itératif
Comment obtenir le nom d'une classe / méthode exécutée en Java
Comment récupérer la valeur de hachage dans un tableau dans Ruby
Comment obtenir les informations les plus longues de Twitter à partir du 12/12/2016
Comment modifier la valeur de réglage de Springboot Hikari CP
[Rails] Comment afficher les informations stockées dans la base de données dans la vue
Comment utiliser Lombok au printemps
Comment obtenir des paramètres dans Spark
Comment définir et utiliser un profil avec une configuration basée sur des annotations dans le framework Spring
Ce que j'ai fait lors de la migration de la série Spring Boot 1.4 vers la série 2.0
Comment obtenir l'identifiant de la clé PRIMAY incrémentée automatiquement dans MyBatis
Comment obtenir la valeur de boolean avec jQuery sous forme simple de rails
Ce que j'ai fait lors de la migration de la série Spring Boot 1.5 vers la série 2.0
Comment obtenir et ajouter des données depuis Firebase Firestore dans Ruby
[Java] Comment convertir du type String en type Path et obtenir le chemin
[Android] Je souhaite obtenir l'auditeur à partir du bouton de ListView
Comment obtenir la longueur d'un fichier audio avec Java
Comment incrémenter la valeur de Map sur une ligne en Java
[Spring Boot] Je veux ajouter mon propre fichier de propriétés et obtenir la valeur avec env.getProperty ().
Comment inclure Spring Tool dans Eclipse 4.6.3?
[Java] Comment obtenir le répertoire actuel
Comment passer la valeur à un autre écran
Comment obtenir la date actuelle sous forme de chaîne au format aaaaMMjj
Essayez d'obtenir des données de la base de données en utilisant MyBatis dans le projet Micronaut + Kotlin
[Rails] Comment obtenir les informations sur l'utilisateur actuellement connecté avec devise
Comment changer la valeur d'une variable à un point d'arrêt dans intelliJ
Comment obtenir le chemin absolu d'un répertoire s'exécutant en Java
Développement Android, comment vérifier null dans la valeur de l'objet JSON
Comment les propriétés de bean lient les paramètres de requête de style liste dans Spring
[Swift] Comment obtenir le nombre d'éléments dans un tableau (super basique)
Comment obtenir les informations d'identification Keycloak dans la classe d'intercepteur
graphql-ruby: Comment obtenir le nom de la requête ou de la mutation dans le contrôleur Remarque
Comment vérifier le journal dans le conteneur Docker
Comment obtenir un heapdump à partir d'un conteneur Docker
Comment obtenir l'ID d'un utilisateur qui s'est authentifié avec Firebase dans Swift
Comment vider de la base de données (DB) vers le fichier de départ
Comment vérifier la dernière version de io.spring.platform pour l'écriture dans pom.xml de Spring (STS)
Comment obtenir le jour d'aujourd'hui
Comment effacer la base de données lors de la recréation de l'application
Mappez les requêtes GET sur des objets complexes dans Spring.
Comment obtenir l'optimisation SIMD pour HotSpot JavaVM
Comment définir des variables d'environnement dans le fichier de propriétés de l'application Spring Boot
Comment obtenir la date du type Date de JavaScript auquel les développeurs C # sont accros
[Java] Comment obtenir l'URL redirigée finale