【问题标题】:Poor man's aspect oriented programming and logging using IDisposable穷人使用 IDisposable 进行面向方面的编程和日志记录
【发布时间】:2014-08-11 19:59:42
【问题描述】:

我的项目中使用任何外部资源(数据库、Web 服务调用等)的每个方法都必须进行日志记录。问题是我最终得到了很多以某种方式重复的代码。句子看起来一样,但它们的参数发生了变化(即方法名称)。

这似乎是重构我的代码的好点。除了 AOP 库之外,我想知道如何至少避免使用魔法字符串并编写一次性对象并将方法体包装在 using 语句中,如下所示:

public void LoggedMethod(int param)
{
    using (new AutoLog())
    {
        // do whatever needs to be done
    }
}

我的AutoLog 类将是一次性的,它将在实例化和处置时写入日志调用。我知道我可能会(ab)为此使用 StackTrace 类,但是 AFAIK 这会大大减慢我的方法,因为这个特定的类非常缓慢。

我的日志条目应该是(当然都包含方法名称):

  • 方法调用的开始
  • 方法调用结束
  • (可选)方法参数 - 当然是序列化的(JSON?)
  • (可选)执行时间

问题

我应该如何实现我的AutoLog 类以尽可能快地工作?如果我还可以读取方法参数那就更好了,这样我就可以将它们序列化并记录它们。

【问题讨论】:

  • 为什么不使用 ProxyDecorator 模式来实现所需的功能?您可以编写自己的实现,也可以使用 Castle Project Dynamci 代理。

标签: logging reflection automation aop idisposable


【解决方案1】:

我的项目中使用任何外部资源(数据库、Web 服务调用等)的每个方法都必须进行日志记录

我简直不敢相信。你可能是logging too much

句子看起来一样,但它们的参数发生了变化(即方法名称)。

在这种情况下,您可能在代码中遗漏了一些通用抽象。根据我的经验,您应该:

对架构上高度相关的代码有一个通用抽象。

this article about command handlers 和这篇关于repositories and custom queries 的文章为例。两篇文章都围绕架构概念定义了一个通用接口。 (您可能应该至少阅读第一篇文章以了解我的其余答案)。

使用通用接口,可以很容易地用装饰器包装一整套相关操作。以这个装饰器为例,它可以包裹所有执行用例的操作:

public class LoggingCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decoratee;
    private readonly ILogger logger;

    public LoggingCommandHandlerDecorator(
        ICommandHandler<TCommand> decoratee,
        ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    void ICommandHandler<TCommand>.Handle(TCommand command)
    {
        using (new AutoLog())
        {
            this.decoratee.Handle(command);
        }
    }
}

我应该如何实现我的 AutoLog 类以尽可能快地工作?

你知道吗,装饰器只是一个薄包装,几乎没有开销。使用这种方法,您通常拥有的所有方法参数现在都打包在一个对象中。这对于日志记录非常方便,因为您可以简单地将整个 TCommand 序列化为 XML、JSon 或更易读的格式,并且您只需编写此代码一次。

而且由于您担心性能,因为这个 LoggingCommandHandlerDecorator&lt;TCommand&gt; 是一个泛型类型,您可以做的是向该类型添加一个静态构造函数(静态构造函数在该接口的每个封闭的泛型版本运行一次)并预编译一些允许您有效地序列化该命令消息的代码。绝对没有任何东西可以与之竞争。甚至 AOP 框架在访问方法的参数时也使用反射并使用装箱构建动态数组。

请注意,像这样应用装饰器并没有什么“穷人”。但是,当您的架构不遵循SOLID 原则时,当您尝试此操作时,您很快就会遇到麻烦。这些原则是获得灵活且可维护的软件的关键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多