【问题标题】:Is there an easy way to create a logger instance for every class?有没有一种简单的方法可以为每个类创建一个记录器实例?
【发布时间】:2014-11-20 11:39:48
【问题描述】:
我现在是用静态方法来记录(因为我觉得在Android上登录很容易),但是现在我需要为不同的类配置不同的appender,所以我对静态记录方法有问题。
我阅读了Log4J: Strategies for creating Logger instances,我注意到是时候更改日志记录策略了,所以我需要在需要特殊记录器的类中添加以下代码。
private static final Logger logger = Logger.getLogger(XXXX.class);
我觉得既然这是重复的工作,那么我们有什么办法可以避免在每个类中添加重复的代码,或者只写更少的代码。 AOP 或依赖注入能做这样的工作吗?
我正在使用 log4j 和 Spring,但任何其他方法都将受到高度赞赏。
【问题讨论】:
标签:
java
spring
logging
dependency-injection
log4j
【解决方案2】:
是的,你可以。
-
创建您的自定义注释说@Logger
@Retention(RUNTIME)//will be used at runtime, so retain till runtime
@Target(FIELD)//field level annotation
public @interface Logger {
}
-
在 Spring 注入的 bean 中将 Logger 字段注释为 @Logger。
@Logger
private Logger logger;
在这里您可以使用 slf4j 记录器,但您可以直接使用 log4j 等。请参阅我如何在此处注释记录器。这是在 Spring 创建的 bean 中。
-
使用名为 BeanPostProcessor 的 Spring 生命周期接口和方法 postProcessBeforeInitialization,使用反射 utils 类来注入记录器。
public class LoggerInjector implements BeanPostProcessor {
/**
* Return the bean itself.
*/
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
return bean;
}
/**
* For all beans before initialization, inject the logger using slf4j.
* @param bean
* @param beanName
* @return returns same bean by injecting logger.
*/
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field);
if (field.getAnnotation(Logger.class) != null) {
if (field.get(bean) == null) {
final Logger logger = LoggerFactory.getLogger(bean.getClass());
field.set(bean, logger);
}
}
}
});
return bean;
}
}
-
完成后,让 spring 知道您有一个记录器注入器,例如:
<bean id="loggerInjector"
class="com.mypackage.LoggerInjector"/>
【解决方案3】:
确实是一个“重复的工作”,为每个需要一个记录器的类添加一个记录器——但是,请记住,即使使用依赖注入,您仍然需要声明方法变量(“记录器”,在您的情况下)。因此,它不会为您节省太多打字时间。
我还建议您使用带有底层实现(如 logback)的日志外观,如 SLF4J。 Logback 由 log4j 的同一作者编写,但更适合 these reasons。如果您确实选择了这条路线(在您的应用中使用 SLF4J),请记住将 jcl-over-slf4j 添加到您的类路径(可能在您的 pom 文件中),因为您使用的是 Spring。
再次关于日志记录策略,可能值得查看 Logback 文档中引用的演示应用程序。示例代码,很像你的,只使用日志外观:
Logger logger = LoggerFactory.getLogger(LoginAction.class);
【解决方案4】:
可以使用工厂方法为您需要的每个记录器在您的上下文中添加一个记录器 bean(尽管这不是通常的方式):
<bean id="logger" scope="prototype" class="org.apache.log4j.Logger" factory-method="getLogger">
<constructor-arg name="name" value="youLoggerName" />
</bean>
那么你可以简单地注入你的记录器:
@Autowired
private Logger logger;