如何解决在单元测试中的 Lombok 实例化之前加载 Spring Boot 组件
我开发了一种 wrapper 以使其作为自定义记录器工作。我正在使用 @CustomLog
Lombok 注释实例化这个类,只是为了使它更容易和更清晰。接下来是棘手的事情:这个包装器背后的想法是使用一个公共记录器(如 org.slf4j.Logger
)以及一个自定义监视器类,每次我调用 log.error()
时,正确的消息都会记录在终端中并将事件发送到我的监控工具(在本例中为 Prometheus)。
为了实现这一点,我做了以下课程:
public final class CustomLoggerFactory {
public static CustomLogger getLogger(String className) {
return new CustomLogger(className);
}
}
-
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);
}
}
-
PrometheusMonitor
类是负责创建指标之类的东西。这里最重要的是它由 Spring Boot 管理。
@Component
public class PrometheusMonitor {
private MeterRegistry meterRegistry;
public PrometheusMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
}
- 您可能已经注意到,要从
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()
方法后,我得到一个异常,原因 context
是 null
。
我的猜测是,如果我可以在 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 举报,一经查实,本站将立刻删除。