启动 Micronaut 应用程序时如何打印环境变量

How to print out environment variables, when starting a Micronaut application

我正在做一个 Micronaut 项目,我想看看当应用程序在本地启动时,来自 application.yml 的环境变量是否使用 @Value 注释正确分配。 但是每次应用程序启动时,它都会显示变量没有分配给 application.yml 文件中的环境变量。

这是我的代码:

public class Application {

    private static String localTestString = "I am the local String";

    @Value("${aws.secretkeyid}")
    public static String applicationYmlTestString;

    @Value("${aws.keyid}")
    private static int keyId;

    public static void main(String[] args) {
        Micronaut.run(Application.class);
    }

    static{
        log.warn("Local Test String is: " + localTestString);
        log.warn("Application Yml Test String is: " + applicationYmlTestString);
        log.warn("Key ID: " + keyId);
    }

}

这是我的application.yml

aws:
  keyid: 123
  secretkeyid: "abcdesdasdsddddd"
  region: "europe-1"

输出:

Local Test String is: I am the local String
Application Yml Test String is: null
Key ID: 0

我们看到两个变量 applicationYmlTestStringkeyId 没有被分配给环境变量。有没有办法解决这个问题并得到:

Application Yml Test String is: abcdesdasdsddddd
Key ID: 123

提前致谢!

您展示的示例存在两个问题。首先,Micronaut 不会向用 @Value 注释注释的静态字段 注入值。 (这并不奇怪,Spring does not support it as well。)其次,在向 non-static 字段注入值后,您将无法使用 class' 静态构造函数读取它们的值。整个应用程序上下文必须准备好读取这些值,因此您需要使用对应用程序启动事件做出反应的事件侦听器。

根据您的示例,这是实现它的最简单方法:

package micronaut.hello.world;

import io.micronaut.context.annotation.Value;
import io.micronaut.context.event.StartupEvent;
import io.micronaut.runtime.Micronaut;
import io.micronaut.runtime.event.annotation.EventListener;
import jakarta.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class Application {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    @Value("${aws.secretkeyid}")
    private String applicationYmlTestString;

    @Value("${aws.keyid}")
    private int keyId;

    public static void main(String[] args) {
        Micronaut.run(Application.class, args);
    }

    @EventListener
    void onStartup(StartupEvent event) {
        log.warn("Application Yml Test String is: " + applicationYmlTestString);
        log.warn("Key ID: " + keyId);
    }

    public String getApplicationYmlTestString() {
        return applicationYmlTestString;
    }

    public void setApplicationYmlTestString(String applicationYmlTestString) {
        this.applicationYmlTestString = applicationYmlTestString;
    }

    public int getKeyId() {
        return keyId;
    }

    public void setKeyId(int keyId) {
        this.keyId = keyId;
    }
}

有三点值得一提:

  1. 上面的例子使用了@EventListener注解,使给定的方法成为“event-aware”,这个方法将在应用程序(或框架)发布特定事件时被触发。
  2. 我们响应 io.micronaut.context.event.StartupEvent - 启动完成后触发的事件。
  3. 请记住,要使此 @EventListener 注释起作用,我们需要使用 @Singleton 注释应用程序 class 以使此 class 成为合适的 Micronaut bean。

或者,如果使应用程序 class 单例 bean 对您来说不合适,您可以实现 ApplicationEventListener 接口并创建一个专用 bean 来响应相同的启动事件。在这个例子中,我使用了一个静态内部class,但这只是为了让这个例子简单:

package micronaut.hello.world;

import io.micronaut.context.annotation.Value;
import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.context.event.StartupEvent;
import io.micronaut.runtime.Micronaut;
import jakarta.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Application {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        Micronaut.run(Application.class, args);
    }

    @Singleton
    static class OnStartupEventListener implements ApplicationEventListener<StartupEvent> {

        @Value("${aws.secretkeyid}")
        private String applicationYmlTestString;

        @Value("${aws.keyid}")
        private int keyId;

        @Override
        public void onApplicationEvent(StartupEvent event) {
            log.warn("Application Yml Test String is: " + applicationYmlTestString);
            log.warn("Key ID: " + keyId);
        }

        public String getApplicationYmlTestString() {
            return applicationYmlTestString;
        }

        public void setApplicationYmlTestString(String applicationYmlTestString) {
            this.applicationYmlTestString = applicationYmlTestString;
        }

        public int getKeyId() {
            return keyId;
        }

        public void setKeyId(int keyId) {
            this.keyId = keyId;
        }
    }
}

但最终,您应该考虑实现配置 class 并使用它而不是使用 @Value 注释注入值。但是,无论您选择什么选项,同样的事情都适用 - 配置 class 可以注入到 non-static 字段,并且可以使用事件侦听器机制进行检查。

正如蒂姆在下面的评论中提到的那样,“尽管记录环境变量要小心......它们有成为秘密的习惯,并且将它们注销往往会以明文告终不同系统负载中的文本“。如果你真的需要在注入预期配置的情况下将此类信息记录到 double-check,请尝试仅在受控开发环境中执行此操作。假设您使用本地环境的 dev 配置文件,您可以使用 @Requires 注释将特定事件侦听器限制为仅 dev 环境:

@Singleton
@Requires(env = "dev")
class OnStartupEventListener implements ApplicationEventListener<StartupEvent> {

    @Value("${aws.secretkeyid}")
    private String applicationYmlTestString;

    @Value("${aws.keyid}")
    private int keyId;

    @Override
    public void onApplicationEvent(StartupEvent event) {
        log.warn("Application Yml Test String is: " + applicationYmlTestString);
        log.warn("Key ID: " + keyId);
    }

    public String getApplicationYmlTestString() {
        return applicationYmlTestString;
    }

    public void setApplicationYmlTestString(String applicationYmlTestString) {
        this.applicationYmlTestString = applicationYmlTestString;
    }

    public int getKeyId() {
        return keyId;
    }

    public void setKeyId(int keyId) {
        this.keyId = keyId;
    }
}