正如问题中提到的,默认情况下,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