Maison  >  Article  >  Java  >  Comment utiliser l'EnvironmentPostProcessor de SpringBoot

Comment utiliser l'EnvironmentPostProcessor de SpringBoot

PHPz
PHPzavant
2023-05-22 09:25:051453parcourir

    1. Contexte

    Le centre de configuration Apollo a été utilisé dans le projet précédent. Après avoir ancré le centre de configuration Apollo, les propriétés du centre de configuration peuvent être utilisées dans le programme. Alors comment. est-ce mis en œuvre ? Quand les propriétés du centre de configuration ont-elles été chargées dans le programme ? Donc, si nous découvrons comment cela est implémenté, pouvons-nous charger les propriétés de configuration de n'importe où et crypter et décrypter les fonctions des propriétés de configuration ? Apollo配置中心,对接Apollo配置中心后,配置中心的属性就可以在程序中使用了,那么这个是怎么实现的呢?配置中心的属性又是何时加载到程序中的呢?那么我们如果找到了这个是怎么实现的是否就可以 从任何地方加载配置属性配置属性的加解密功能呢

    二、需求

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    从上图中得知,我们的需求很简单,即我们自己定义的属性需要比配置文件中的优先级更高。

    三、分析

    1、什么时候向SpringBoot中加入我们自己的配置属性

    当我们想在Bean中使用配置属性时,那么我们的配置属性必须在Bean实例化之前就放入到Spring到Environment中。即我们的接口需要在 application context refreshed 之前进行调用,而 EnvironmentPostProcessor 正好可以实现这个功能。

    2、获取配置属性的优先级

    我们知道在 Spring中获取属性是有优先级的。
    比如我们存在如下配置属性 username

    ├─application.properties
    │   >> username=huan
    ├─application-dev.properties
    │   >> username=huan.fu

    那么此时 username 的值是什么呢?此处借用 Apollo的一张图来说解释一下这个问题。

    参考链接:https://www.apolloconfig.com/#/zh/design/apollo-design

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    Spring从3.1版本开始增加了ConfigurableEnvironmentPropertySource

    ConfigurableEnvironment
    • Spring的ApplicationContext会包含一个Environment(实现ConfigurableEnvironment接口)

    • ConfigurableEnvironment自身包含了很多个PropertySource

    PropertySource

    • 属性源

    • 可以理解为很多个Key - Value的属性配置

    由上方的原理图可知,key在最开始出现的PropertySource中的优先级更高,上面的例子在SpringBootusername的值为huan.fu

    3、何时加入我们自己的配置

    由第二步 获取配置属性的优先级 可知,PropertySource 越靠前越先执行,那么要我们配置生效,就必须放在越前面越好。

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    由上图可知,SpringBoot加载各种配置是通过EnvironmentPostProcessor来实现的,而具体的实现是ConfigDataEnvironmentPostProcessor来实现的。那么我们自己编写一个EnvironmentPostProcessor的实现类,然后在ConfigDataEnvironmentPostProcessor后执行,并加入到 Environment中的第一位即可。

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    四、实现

    1、引入SpringBoot依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.6</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.huan.springcloud</groupId>
        <artifactId>springboot-extension-point</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springboot-extension-point</name>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    </project>

    2、在application.properties中配置属性

    vim application.properties
    username=huan

    3、编写自定义属性并加入Spring Environment中

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    注意:
    1、如果发现程序中日志没有输出,检查是否使用了slf4j输出日志,此时因为日志系统未初始化无法输出日志。解决方法如下:

    SpringBoot版本
    		>= 2.4 可以参考上图中的使用 DeferredLogFactory 来输出日志
    		< 2.4
    			1、参考如下链接 https://stackoverflow.com/questions/42839798/how-to-log-errors-in-a-environmentpostprocessor-execution
    			2、核心代码:
    				@Component
    				public class MyEnvironmentPostProcessor implements
    				        EnvironmentPostProcessor, ApplicationListener<ApplicationEvent> {
    				    private static final DeferredLog log = new DeferredLog();
    				    @Override
    				    public void postProcessEnvironment(
    				            ConfigurableEnvironment env, SpringApplication app) {
    				        log.error("This should be printed");
    				    }
    				    @Override
    				    public void onApplicationEvent(ApplicationEvent event) {
    				        log.replayTo(MyEnvironmentPostProcessor.class);
    				    }
    				}

    4、通过SPI使自定义的配置生效

    1、在 src/main/resources下新建META-INF/spring.factories文件

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    2、配置

    org.springframework.boot.env.EnvironmentPostProcessor=\
      com.huan.springcloud.extensionpoint.environmentpostprocessor.CustomEnvironmentPostProcessor

    5、编写测试类,输出定义的 username 属性的值

    @Component
    public class PrintCustomizeEnvironmentProperty implements ApplicationRunner {
    
        private static final Logger log = LoggerFactory.getLogger(PrintCustomizeEnvironmentProperty.class);
        @Value("${username}")
        private String userName;
        @Override
        public void run(ApplicationArguments args) {
            log.info("获取到的 username 的属性值为: {}", userName);
        }
    }

    6、运行结果

    Comment utiliser lEnvironmentPostProcessor de SpringBoot

    五、注意事项

    1、日志无法输出

    参考上方的 3、编写自定义属性并加入Spring Environment中

    2. Exigences

    Comment utiliser l'environnement PostProcessor de SpringBoot
    • D'après la figure ci-dessus, nous savons que notre exigence est très simple, c'est-à-dire que les propriétés que nous définissons doivent avoir une priorité plus élevée que celles du fichier de configuration.

      3. Analyse🎜

      1. Quand ajouter nos propres propriétés de configuration à SpringBoot

      🎜Lorsque nous voulons utiliser les propriétés de configuration dans un Bean, alors nos propriétés de configuration doivent être dans le Bean Put. dans Spring et Environment avant l'instanciation. Autrement dit, notre interface doit être appelée avant que le contexte d'application ne soit actualisé, et EnvironmentPostProcessor peut exactement implémenter cette fonction. 🎜

      2. La priorité d'obtention des propriétés de configuration

      🎜Nous savons qu'il existe une priorité pour l'obtention des propriétés au Spring.
      Par exemple, nous avons l'attribut de configuration suivant username🎜
      org.springframework.boot.context.logging.LoggingApplicationListener
      🎜Alors, quelle est la valeur de username à ce moment ? Ici, j'emprunte une image à Apollo pour expliquer ce problème. 🎜🎜Lien de référence : https://www.apolloconfig.com/#/zh/design/apollo-design🎜🎜Comment utiliser EnvironmentPostProcessor de SpringBoot🎜🎜Spring a ajouté ConfigurableEnvironment et PropertySource depuis la version 3.1 : 🎜rrreee🎜🎜🎜Spring ApplicationContext sera contenir un environnement (implémentant l'interface ConfigurableEnvironment)🎜
    • 🎜🎜ConfigurableEnvironment lui-même contient de nombreuses PropertySources🎜🎜🎜PropertySource🎜🎜🎜🎜Property Sources🎜 🎜🎜peut être compris comme de nombreuses configurations de propriétés clé-valeur🎜🎜🎜Comme le montre le diagramme schématique ci-dessus, key apparaît dans le premier PropertySource. La priorité est plus élevée . Dans l'exemple ci-dessus, la valeur de username dans SpringBoot est huan.fu. 🎜

      3. Quand ajouter notre propre configuration

      🎜Dès la deuxième étape Obtenir la priorité des propriétés de configuration nous pouvons voir que plus la PropertySource est élevée. c'est-à-dire que plus il est Exécution, alors pour que notre configuration prenne effet, elle doit être placée le plus tôt possible. 🎜🎜Comment utiliser l'EnvironmentPostProcessor de SpringBoot🎜🎜Comme vous pouvez le voir sur le Dans l'image ci-dessus, SpringBoot Le chargement de diverses configurations est réalisé via EnvironmentPostProcessor, et l'implémentation spécifique est réalisée par ConfigDataEnvironmentPostProcessor. Ensuite, nous écrivons nous-mêmes une classe d'implémentation de EnvironmentPostProcessor, puis l'exécutons après ConfigDataEnvironmentPostProcessor et l'ajoutons à la première position dans Environment. 🎜🎜Comment utiliser l'EnvironmentPostProcessor de SpringBoot🎜🎜Quatre implémentations🎜1. Introduisez les dépendances SpringBootrrreee

      2. Configurez les propriétés dans application.properties

      rrreeerrreee

      3. Écrivez des propriétés personnalisées et ajoutez-les à Spring Environment

      🎜Comment utiliser EnvironmentPostProcessor de SpringBoot🎜🎜Remarque :
      1. trouvé Il n'y a aucune sortie dans le journal. Vérifiez si slf4j est utilisé pour sortir le journal. À ce stade, le journal ne peut pas être sorti car le système de journalisation n'a pas été initialisé. La solution est la suivante :🎜rrreee

      4. Faites prendre en compte la configuration personnalisée via SPI

      🎜1 Créez un nouveau src/main/resources<.> >META-INF/spring.factories</.>Fichier🎜🎜 EnvironmentPostProcessor de SpringBoot Comment utiliser🎜🎜2. Configuration🎜rrreee

      5. Écrivez une classe de test et affichez la valeur de l'attribut de nom d'utilisateur défini

      rrreee

      6. Résultats d'exécution

      🎜 Comment utiliser l'EnvironmentPostProcessor de SpringBoot🎜🎜5 Notes🎜

      1. . Le journal ne peut pas être généré

      🎜Référez-vous à la solution fournie par 3 Écrivez des attributs personnalisés et ajoutez-les à Spring Environment ci-dessus. 🎜🎜2. La configuration ne prend pas effet. Vérifiez la priorité de EnvironmentPostProcessor pour voir si la valeur de priorité renvoyée par @Order ou Ordered est incorrecte. 🎜
    • 看看别的地方是否实现了 EnvironmentPostProcessor或ApplicationContextInitializer或BeanFactoryPostProcessor或BeanDefinitionRegistryPostProcessor等这些接口,在这个里面修改了 PropertySource的顺序。

    • 理解 Spring 获取获取属性的顺序 参考 2、获取配置属性的优先级

    3、日志系统如何初始化

    如下代码初始化日志系统

    org.springframework.boot.context.logging.LoggingApplicationListener

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer