微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在单元测试中的 Lombok 实例化之前加载 Spring Boot 组件

如何解决在单元测试中的 Lombok 实例化之前加载 Spring Boot 组件

我开发了一种 wrapper 以使其作为自定义记录器工作。我正在使用 @CustomLog Lombok 注释实例化这个类,只是为了使它更容易和更清晰。接下来是棘手的事情:这个包装器背后的想法是使用一个公共记录器(如 org.slf4j.Logger)以及一个自定义监视器类,每次我调用 log.error() 时,正确的消息都会记录在终端中并将事件发送到我的监控工具(在本例中为 Prometheus)。

为了实现这一点,我做了以下课程:

  1. CustomLoggerFactory Lombok 调用的工厂来实例化我的自定义记录器。
public final class CustomLoggerFactory {

     public static CustomLogger getLogger(String className) {

        return new CustomLogger(className);
     }
}
  1. CustomLogger 将收到类名,然后调用 org.slf4j.LoggerFactory
public class CustomLogger {

    private org.slf4j.Logger logger;
    private PrometheusMonitor prometheusMonitor;
    private String className;

    public CustomLogger(String className) {

        this.logger = org.slf4j.LoggerFactory.getLogger(className);
        this.className = className;
        this.monitor = SpringContext.getBean(PrometheusMonitor.class);
    }
}
  1. PrometheusMonitor 类是负责创建指标之类的东西。这里最重要的是它由 Spring Boot 管理
@Component
public class PrometheusMonitor {

    private MeterRegistry meterRegistry;

    public PrometheusMonitor(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
}
  1. 您可能已经注意到,要从 PrometheusMonitor 访问 CustomLogger,我需要一个额外的类,以便从非 Spring 托管类获取 Bean/访问上下文。这是 SpringContext 类,它有一个 static 方法可以通过提供的类获取 bean。
@Component
public class SpringContext implements ApplicationContextAware {

    private static ApplicationContext context;

    public static <T extends Object> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        SpringContext.context = context;
    }
}

所以所有这些在运行应用程序时都可以正常工作。我确保在其他任何事情之前加载 SpringContext 类,因此一旦每个 CustomLogger 被实例化,它就可以正常工作。

但是 问题出现了:这在对我的应用程序进行单元测试时不起作用。我尝试了很多东西,我看到了一些可能对我有帮助但我试图避免的解决方案(例如使用 powermockito)。 Lombok 在我添加到测试类的任何 @CustomLog 方法之前处理 @Before 注释。调用 getBean() 方法后,我得到一个异常,原因 contextnull

我的猜测是,如果我可以在 Lombok 发挥其魔力之前强制加载 SpringContext,我可以解决它,但我不确定这是否可能。非常感谢您花时间阅读本文。我能提供的更多信息请告诉我。

解决方法

注意:听起来像往常一样登录到 slf4j 可以更好地满足您的自定义日志记录需求,并在 slf4j 框架中注册一个额外的处理程序,以便 slf4j 将任何日志转发给您(除了其他处理程序,例如制作日志文件的那个)。

Lombok 正在处理 @CustomLog

生成的日志字段是静态的。如果注释有帮助,您将需要 @BeforeClass,但这可能也不及时。龙目岛的魔法在这里似乎无关紧要。看看 delombok 告诉你 lombok 正在做什么:它只是..一个静态字段,在声明时被初始化。

,

好吧,我设法解决了这个问题,稍微改变了 CustomLogger 的工作方式。这意味着您可以在第一次使用它时进行实例化,而不是将 monitor 字段与记录器一起实例化。例如:

public class CustomLogger {

    private org.slf4j.Logger logger;
    private Monitor monitor;

    public CustomLogger(String className) {
        this.logger = org.slf4j.LoggerFactory.getLogger(className);
    }

    public void info(String message) {
        this.logger.info(message);
    }

    public void error(String message) {
        this.logger.error(message);
        if (this.monitor == null) {
            this.monitor = SpringContext.getBean(PrometheusMonitor.class);
        }
        this.monitor.send(message);
    }
}

但毕竟我决定不采用这种方法,因为我认为这不是最好的方法,也不值得。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。