查看使用a project for .NET的Common.Logging,我注意到有些类将logger实例声明为类静态成员。例如:
public class HelloJob : IJob
{
private static ILog _log = LogManager.GetLogger(typeof(HelloJob));
public HelloJob()
{
}
public virtual void Execute(IJobExecutionContext context)
{
_log.Info(string.Format("Hello World! - {0}", System.DateTime.Now.ToString("r")));
}
}
在其他类中,记录器被声明为实例成员:
public class SimpleExample : IExample
{
public virtual void Run()
{
ILog log = LogManager.GetLogger(typeof (SimpleExample));
log.Info("------- Initializing ----------------------");
// etc
}
}
是否有理由选择一种方法或另一种方法?
建议采用哪种方法?它与线程安全有关吗?
如果我刚刚宣布一个带有静态“记录器”成员的“Logger”类并且使用了整个项目(除了我在实践中会有一个全局变量的问题),这会是一个问题吗?
答案 0 :(得分:9)
大多数记录器都是线程安全的,并且创建它们的实例在时间和内存方面都有很小的开销。因此,真正的问题需要从编程和可维护性的角度来看是有意义的。
一方面,由于记录器在概念上与类相关联,而不是与类的实例相关联,因此很多人更喜欢将其保持静态。这是一个非常有效的论点。例如,如果HelloWorldJob
扩展HelloJob
,我认为大多数人都希望HelloJob
中的代码编写的日志消息与HelloJob
类绑定,即使您有一个更具体的子类实例。能够从静态方法访问您的记录器也很好,如果它不在静态字段上,这是不可能的。
另一方面,没有理由让HelloJob负责获取自己的记录器实例。对于使用依赖注入(单元可测试性,附加可配置性和更简单的代码),有很多要说的。因此,我个人建议让您的记录器由DI框架注入,在这种情况下,需要在每个实例字段上引用它。
public class HelloJob : IJob
{
private readonly ILog _log;
public HelloJob(ILog log)
{
_log = log;
}
...
}
您的DI框架可以根据它在运行时知道的详细信息设置记录器,或者您可以在单元测试中提供假的或模拟的记录器,以确保生成预期的日志消息。请注意,即使您指的是每个实例字段,您仍可以完全自由地使用每个类(甚至是单个)实例 - 这些只是不需要成为此类的一部分的详细信息关注。