我目前正在考虑升级中型到大型 Java 代码库中的日志记录机制。当前使用Debug
类上的静态方法记录消息,我建议将其切换到 SLF4J 或 commons-logging 之类的东西。
应用程序架构师更喜欢我封装对 SLF4J 的依赖(可能通过将其包装在上述Debug
类中)。这将使将来更容易更改日志记录实现。
这对我来说似乎有点矫枉过正,因为 SLF4J 已经抽象了具体的日志记录实现。
是否值得将 SLF4J 之类的第 3 方日志抽象封装在另一个本土抽象中?
我目前正在考虑升级中型到大型 Java 代码库中的日志记录机制。当前使用Debug
类上的静态方法记录消息,我建议将其切换到 SLF4J 或 commons-logging 之类的东西。
应用程序架构师更喜欢我封装对 SLF4J 的依赖(可能通过将其包装在上述Debug
类中)。这将使将来更容易更改日志记录实现。
这对我来说似乎有点矫枉过正,因为 SLF4J 已经抽象了具体的日志记录实现。
是否值得将 SLF4J 之类的第 3 方日志抽象封装在另一个本土抽象中?
我完全同意你的观点:包装器的包装器正在失控。我怀疑架构师没有意识到特别是 SLF4J 可以轻松地包装任何其他日志记录系统,因此“更改实现”在没有另一层包装的情况下是完全可行的。
我猜架构师希望包装包装器(即 SLF4J)背后的动机是将您的应用程序与 SLF4J 隔离开来。显然,从应用程序中调用 SLF4J API 会创建对 SLF4J 的依赖。然而,想要重复应用隔离原则同样合理,如下所述。这让我想起了理查德·道金斯的问题:如果上帝创造了宇宙,那么是谁创造了上帝?
实际上,您也可以在包装 SLF4J 的包装器上应用隔离原则。如果 SLF4J 包装器在某种程度上不如 SLF4J,那么隔离的原因将是不利的。尽管有可能,但包装器很少能达到或超过原始包装器。SWT 可以作为一个值得注意的反例来引用。然而,SWT 是一个相当大的项目,成本很高。更重要的是,根据定义,SLF4J 包装器依赖于 SLF4J。它必然具有相同的通用 API。如果将来出现一个新的、显着不同的日志 API,那么使用包装器的代码将与直接使用 SLF4J 的代码一样难以迁移到新的 API。因此,包装器不太可能对您的代码进行未来验证,而是通过添加额外的间接来使其更重。
简而言之,即使您没有更好的事情可做,也不应该浪费时间包装 SLF4J,因为包装器的附加值保证接近于零。
该主题也在SLF4J FAQ 条目中提出。
我宁愿把它包起来,但不是出于上述原因。如果关注的是换出另一个框架的能力,请使用 java.util.logging 或 SLF(java.util.logging 不像包装器那样容易使用,但它非常可行),然后换掉。使用(又一个)包装器的原因是在代码中编写适当的日志记录方式。通常,应用程序需要一个子集,例如所有系统错误都带有异常,或者有关于何时使用标准日志记录级别的特定指导。这些决策可以封装在一些方法中,在大型代码库上创建更一致的日志记录决策。
但是,如果动机只是为了让替换实现成为可能,请不要重新发明轮子。SLF 非常适合这项工作,只需使用它。
有一个例外。如果您的代码旨在无缝地部署到许多可能的应用程序服务器中,则您必须确保您的日志记录选择不会与框架使用的任何旧版本或新版本发生冲突。
向您的架构宇航员解释slf4j 已经可以充当其他日志记录实现的包装器,例如 log4j。所以如果你将来需要使用一些其他的记录器并且没有slf4j的适配器,你可以在需要的时候编写它,但它只是适配器,而不是写一个完整的日志框架,只会包装一些其他的日志框架,您需要为此设计框架并编写自己的适配器。
每个包装器的问题在于您将如何实际包装以及您将提供哪些功能:
我不知道您当前的 Debug 类,但我想它非常基础。
你可能不会有像
如果您的 Debug 类非常基本,这对您来说实际上非常好:)
这意味着您可能能够通过执行全局搜索和删除来切换到 SLF4J... 错误... 替换。
做备份,虽然... ;)
另请参阅新项目是否应该使用 logback 而不是 log4j?,用 Java 登录是怎么回事?,选择哪个log4j门面?,在java日志框架场景中寻找方法。你觉得 java.util.logging 足够了吗?. (剧透:你不应该使用 java.util.logging,拜托了)
如果您正在考虑在未来切换 Logging 框架,可能值得添加一个额外的层来切换记录器。否则,如果他们提供了你可能需要的一切(当然,使用你的水晶球),那么对那个框架有一个硬依赖可能是可以的。
如果您当前的设置允许灵活更改,则不需要包装器。