Java 在单元测试中Lombok实例化之前加载Spring启动组件

Java 在单元测试中Lombok实例化之前加载Spring启动组件,java,spring,spring-boot,junit4,lombok,Java,Spring,Spring Boot,Junit4,Lombok,我开发了一种包装器,使其能够作为自定义记录器工作。我正在使用@CustomLogLombok注释实例化这个类,只是为了使它更简单、更干净。接下来是一件棘手的事情:这个包装器背后的想法是使用一个通用的记录器(如org.slf4j.logger)和一个自定义的监控类,每次我调用log.error(),正确的消息都会被记录在终端中,事件会被发送到我的监控工具(本例中是普罗米修斯) 为了实现这一点,我上了以下课程: CustomLoggerFactoryLombok调用的工厂,用于实例化我的自定义记录器

我开发了一种包装器,使其能够作为自定义记录器工作。我正在使用
@CustomLog
Lombok注释实例化这个类,只是为了使它更简单、更干净。接下来是一件棘手的事情:这个包装器背后的想法是使用一个通用的记录器(如
org.slf4j.logger
)和一个自定义的监控类,每次我调用
log.error()
,正确的消息都会被记录在终端中,事件会被发送到我的监控工具(本例中是普罗米修斯)

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

  • CustomLoggerFactory
    Lombok调用的工厂,用于实例化我的自定义记录器
  • 公共最终类CustomLoggerFactory{
    公共静态CustomLogger getLogger(字符串类名称){
    返回新的CustomLogger(类名);
    }
    }
    
  • CustomLogger
    将收到类名,然后调用
    org.slf4j.LoggerFactory
  • 公共类自定义记录器{
    私有org.slf4j.Logger;
    私人PrometheusMonitor PrometheusMonitor;
    私有字符串类名;
    公共CustomLogger(字符串类名称){
    this.logger=org.slf4j.LoggerFactory.getLogger(类名);
    this.className=className;
    this.monitor=SpringContext.getBean(PrometheusMonitor.class);
    }
    }
    
  • PrometheusMonitor
    类是负责创建度量标准之类的东西的类。这里最重要的是,它由Spring Boot管理
  • @组件
    公共类PrometheusMonitor{
    私人计量登记;
    公共PrometheusMonitor(计量登记计量登记){
    this.meterRegistry=meterRegistry;
    }
    }
    
  • 您可能注意到,要从
    CustomLogger
    访问
    PrometheusMonitor
    ,我需要一个额外的类,以便从非Spring管理的类获取Bean/访问上下文。这是
    SpringContext
    类,它有一个
    static
    方法通过提供的类获取bean
  • @组件
    公共类SpringContext实现ApplicationContextAware{
    私有静态应用上下文上下文;
    公共静态T getBean(类beanClass){
    返回context.getBean(beanClass);
    }
    @凌驾
    public void setApplicationContext(ApplicationContext上下文)引发BeansException{
    SpringContext.context=context;
    }
    }
    
    因此,在运行应用程序时,所有这些都可以正常工作。我确保先加载
    SpringContext
    类,所以一旦每个
    CustomLogger
    被实例化,它就可以工作了

    但是这里出现了一个大问题:在对我的应用程序进行单元测试时,这不起作用。我尝试了很多方法,发现了一些可能对我有帮助但我正在努力避免的解决方案(例如使用PowerMockito)。Lombok正在处理我添加到测试类中的任何
    @before
    方法之前的
    @CustomLog
    注释。调用
    getBean()
    方法后,我会得到一个异常原因
    context
    null


    我的猜测是,如果我能在Lombok变魔术之前强制加载
    SpringContext
    ,我就可以解决这个问题,但我甚至不确定这是否可能。非常感谢您花时间阅读此文章。我能提供的更多信息,请告诉我。

    注意:像平常一样登录到slf4j,并在slf4j框架中注册一个额外的处理程序,这样slf4j将向您转发任何日志(除了其他处理程序之外,例如生成日志文件的处理程序),似乎可以更好地满足您的自定义日志记录需求

    Lombok正在处理@CustomLog


    生成的日志字段是静态的。如果注释有任何帮助,您需要在类之前使用
    @BeforeClass
    ,但这可能也不及时。龙目山的魔法在这里似乎不相关。看看delombok告诉你lombok在做什么:它只是。。一个静态字段,在声明时初始化。

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

    公共类自定义记录器{
    私有org.slf4j.Logger;
    私人监听;
    公共CustomLogger(字符串类名称){
    this.logger=org.slf4j.LoggerFactory.getLogger(类名);
    }
    公共无效信息(字符串消息){
    this.logger.info(消息);
    }
    公共无效错误(字符串消息){
    此.logger.error(消息);
    if(this.monitor==null){
    this.monitor=SpringContext.getBean(PrometheusMonitor.class);
    }
    此.monitor.send(消息);
    }
    }
    

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

    起初我是这样想的(处理其他框架发送的日志事件)但是对于我现在拥有的日志,我使用了一些自定义参数,如
    enum
    s,这些参数不能与Slf4j日志调用一起发送。所以我看不到一种处理方法可以满足我的需要。