当前位置: 首页 > 知识库问答 >
问题:

使用Spring Boot向Logback Appenders注入依赖项

尉迟雅昶
2023-03-14

如果不可能,实现我的目标(将bean从应用程序上下文插入到appender中)的规范方法是什么?

共有1个答案

叶翰林
2023-03-14

正如问题中提到的,默认情况下,Logback实例化并管理不同日志记录组件(追加器等)本身的生命周期。它对Spring一无所知。而且,Logback通常会在Spring启动之前自行配置(因为Spring也使用它进行日志记录)。

因此,您不能真正使用Spring来配置FileAppender(或其他一些相当基本的appender)的实例,然后将其注入到logback中。

但是,如果您的appender不是真正的基础(或者您很乐意在Spring Boot启动期间忽略日志事件),您可以遵循下面的“简单”方法。如果您想捕获所有事件(包括启动期间的事件),请继续阅读。

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

@Component
public class LogbackCustomAppender extends UnsynchronizedAppenderBase<ILoggingEvent> implements SmartLifecycle {

  @Override
  protected void append(ILoggingEvent event) {
    // TODO handle event here
  }

  @Override
  public boolean isRunning() {
    return isStarted();
  }

}

正如您所看到的,它用@component进行了注释,这样Spring就可以在类路径扫描期间提取它。此外,它实现了SmartLifecycle,以便Spring调用LogbackLifecycle接口方法(幸运的是,start()stop()方法具有完全相同的签名,因此我们只需要实现isrunning(),它将委托给Logbackisstart())。

现在,在Spring应用程序上下文启动结束时,我们可以检索完全初始化的LogbackCustomAppender实例。但是Logback很幸运地不知道这个追加器,所以我们需要用Logback注册它。

其中一种方法是在Spring Boot应用程序类中:

@SpringBootApplication
@ComponentScan(basePackages = {"net.my.app"})
public class CustomApplication {

  public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext context = SpringApplication.run(CustomApplication.class, args);
    context.start();
    addCustomAppender(context, (LoggerContext) LoggerFactory.getILoggerFactory());
  }

  private static void addCustomAppender(ConfigurableApplicationContext context, LoggerContext loggerContext) {
    LogbackErrorCollector customAppender = context.getBean(LogbackCustomAppender.class);
    Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
    rootLogger.addAppender(customAppender);
  }

}

不需要更改您的日志配置文件中的任何内容。

更复杂的方法(捕获所有事件)

如上所述,您可能对在Spring Boot启动期间不丢失记录的事件感兴趣。

为此,您可以实现一个占位符追加器(它将在内部缓冲启动事件):

import ch.qos.logback.core.Appender;
import ch.qos.logback.core.UnsynchronizedAppenderBase;

import java.util.ArrayList;

public class BufferingAppenderWrapper<E> extends UnsynchronizedAppenderBase<E> {

  private final ArrayList<E> eventBuffer = new ArrayList<>(1024);
  private Appender<E> delegate;

  @Override
  protected void append(E event) {
    synchronized (eventBuffer) {
      if (delegate != null) {
        delegate.doAppend(event);
      }
      else {
        eventBuffer.add(event);
      }
    }
  }

  public void setDelegateAndReplayBuffer(Appender<E> delegate) {
    synchronized (eventBuffer) {
      this.delegate = delegate;
      for (E event : this.eventBuffer) {
        delegate.doAppend(event);
      }
      this.eventBuffer.clear();
    }
  }

}

我们以通常的方式(例如Logback.xml)使用Logback注册该appender:

  <appender name="DELEGATE" class="my.app.BufferingAppenderWrapper" />

  <root level="INFO">
    <appender-ref ref="DELEGATE" />
  </root>

Spring启动后,按名称查找appender,并用占位符注册Spring配置的appender(在进程中刷新缓冲的事件):

@SpringBootApplication
@ComponentScan(basePackages = {"net.my.app"})
public class CustomApplication {

  public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext context = SpringApplication.run(CustomApplication.class, args);
    context.start();
    addCustomAppender(context, (LoggerContext) LoggerFactory.getILoggerFactory());
  }

  private static void addCustomAppender(ConfigurableApplicationContext context, LoggerContext loggerContext) {
    LogbackErrorCollector customAppender = context.getBean(LogbackCustomAppender.class);
    Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
    BufferingAppenderWrapper<ILoggingEvent> delegate = (BufferingAppenderWrapper<ILoggingEvent>) rootLogger.getAppender("DELEGATE");
    delegate.setDelegateAndReplayBuffer(customAppender);
  }

}
 类似资料:
  • 我有一个控制器 服务接口 我想在我的控制器中使用@autowired来使用该服务,但当我运行应用程序时,我得到以下错误 org.springframework.beans.factory.beanCreationException:创建名为“demo application”的bean时出错:注入autowired依赖项失败;嵌套异常为org.SpringFramework.Beans.Facto

  • 我想向Springbean注入一个单例对象依赖关系。问题是我无法访问和修改要注入其对象的类。让我描述一下这个例子。 所以我有我的接口,以及这个接口的实现,如下所示。 然后在我的配置类中,我正在创建一个bean,但是我需要在构造函数中向它传递对象,问题是我不能使成为bean,因为它来自外部包,我不能修改它。 所以我想做的是,能够将/autowire参数传递给bean。目前IntelliJ给我一个错误

  • 我有一个这样定义的单例实例: 现在,由于一些变化,这个类必须依赖于几个(3)依赖项。因此,这些依赖项必须在这里注入。 我们如何为这样设计的Singleton类实现依赖注入? 问题是,已经有很多调用方,因此无法使 getInstance 方法来接受依赖关系。 页(page的缩写)我知道使用单例并不总是一种更干净的方式:)(这是现有的代码,我不得不忍受它:) 附注:我正在使用Guice进行依赖注入。

  • 在React中,想做依赖注入(Dependency Injection)其实相当简单。请看下面这个例子: // Title.jsx export default function Title(props) { return <h1>{ props.title }</h1>; } // Header.jsx import Title from './Title.jsx'; export defa

  • 依赖注入 Dependency Injection is a strong mechanism, which helps us easily manage dependencies of our classes. It is very popular pattern in strongly typed languages like C# and Java. 依赖注入是一个很强大的机制,该机制可以帮

  • 简介 Hyperf 默认采用 hyperf/di 作为框架的依赖注入管理容器,尽管从设计上我们允许您更换其它的依赖注入管理容器,但我们强烈不建议您更换该组件。 hyperf/di 是一个强大的用于管理类的依赖关系并完成自动注入的组件,与传统依赖注入容器的区别在于更符合长生命周期的应用使用、提供了 注解及注解注入 的支持、提供了无比强大的 AOP 面向切面编程 能力,这些能力及易用性作为 Hyper