今天启动tomcat服务失败,碰到异常情况如下
java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
at org.apache.commons.logging.impl.SLF4JLocationAwareLog.info(SLF4JLocationAwareLog.java:159)
Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突...
和平的日子不在了,让我们一起来看看究竟发生了什么...
首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。
为什么commons-logging和jcl-over-slf4j会有冲突呢?看一下它们的类结构
很清晰的可以看到jcl-over-slf4j 重写了 commons-logging...
还有slf4j-api的实现呢,同样看类:
其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。
顺着研究,继续看一下slf4j的源码及流程
1.测试类
package com.taobao.wuzhong.log; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DESC: * * Copyright: Copyright 2011 m.taobao.com * * @author wuzhong@taobao.com * @time 2011-4-6 下午03:42:11 * @version 1.0 **/ public class LogTest { // Logback tries to find a file called logback.groovy in the classpath. // If no such file is found, logback tries to find a file called // logback-test.xml in the classpath. // If no such file is found, it checks for the file logback.xml in the // classpath.. // If neither file is found, logback configures itself automatically using // the BasicConfigurator which will cause logging output to be directed to // the console. @Test public void test() { //commons-logging的方式获取 Log log = LogFactory.getLog(LogTest.class); //slf4j直接的方式获取,推荐用这个 Logger log2 = LoggerFactory.getLogger(LogTest.class); log.debug("eeeeee {} {} {}"); log2.debug("{} {} {}", new String[] { "a", "b", "c" }); } }
logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
Log instance = null;
// protect against concurrent access of loggerMap
synchronized (this) {
instance = (Log) loggerMap.get(name);
if (instance == null) {
Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了
if(logger instanceof LocationAwareLogger) {
instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger); //包装了一层,做适配
} else {
instance = new SLF4JLog(logger);
}
loggerMap.put(name, instance);
}
}
return (instance);
loggerFactory 会调用getILoggerFactory().getlOgger()
LoggerFactory.java public static ILoggerFactory getILoggerFactory() { if (INITIALIZATION_STATE == UNINITIALIZED) { INITIALIZATION_STATE = ONGOING_INITILIZATION; performInitialization(); } switch (INITIALIZATION_STATE) { case SUCCESSFUL_INITILIZATION: return getSingleton().getLoggerFactory(); case FAILED_INITILIZATION: throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); case ONGOING_INITILIZATION: // support re-entrant behavior. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 return TEMP_FACTORY; } throw new IllegalStateException("Unreachable code"); } private final static void performInitialization() { bind(); versionSanityCheck(); singleImplementationSanityCheck(); }
这里的bind很关键,这里动态的绑定了slf4j-api的实现机制
static { SINGLETON.init(); } /** * Package access for testing purposes. */ void init() { try { try { new ContextInitializer(defaultLoggerContext).autoConfig(); } catch (JoranException je) { Util.reportFailure("Failed to auto configure default logger context", je); } StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); contextSelectorBinder.init(defaultLoggerContext, KEY); initialized = true; } catch (Throwable t) { // we should never get here Util.reportFailure("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); } }
获取配置信息初始化
autoConfig …. public URL findURLOfDefaultConfigurationFile(boolean updateStatus) { ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this); URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus); if (url != null) { return url; } url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader); if (updateStatus) { statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url); } if (url != null) { return url; } url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader); if (updateStatus) { statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url); } return url; } public void autoConfig() throws JoranException { StatusListenerConfigHelper.installIfAsked(loggerContext); URL url = findURLOfDefaultConfigurationFile(true); if (url != null) { configureByResource(url); } else { BasicConfigurator.configure(loggerContext); } }
最后画张流程图总结下,^_^
总结: log框架应该很好的诠释了 facade , adapter , 实现上还是比较简单的,很好的做到了接口和实现的分离,对今后的代码组织有一定的启发
相关推荐
Log4Qt是Qt框架下的一款日志记录库,它基于流行的Java日志库log4j设计,为C++开发者提供了一套强大、灵活的日志处理机制。本文将深入探讨Log4Qt日志管理的核心概念、功能特性以及如何在实际项目中有效应用。 一、...
本文将深入探讨“c# log日志类和日志分析器”的相关知识点,包括日志的创建、存储、分析以及提供的源码在实际项目中的应用。 首先,让我们了解什么是日志。日志是程序运行过程中产生的事件记录,这些记录包含了...
通过以上介绍,我们可以看出Log4j日志框架在Java开发中的重要地位,它不仅简化了日志处理,还为故障排查、性能分析和系统监控提供了有力支持。正确使用和配置Log4j,将有助于提升软件质量和维护效率。
在IT行业中,日志框架是不可或缺的工具,它主要用于记录应用程序运行时的详细信息,帮助开发者在调试、问题排查和性能优化过程中获取关键数据。"采用JDK实现的日志框架"是一个基于Java Development Kit(JDK)1.4中...
此外,C++标准库并没有提供内置的日志框架,但在实际开发中,很多开发者会使用第三方库,如Glog、spdlog等,它们提供了更强大、更灵活的功能,例如异步日志处理、自定义格式化和日志过滤等。 总之,通过理解日志...
【SSH+Maven+Bootstrap视频教程】第18章主要讲解了如何测试并应用Log4j日志框架,这是Java开发中的一个关键组件,尤其在系统监控、调试和错误跟踪方面发挥着重要作用。Log4j是Apache软件基金会的一个开放源代码项目...
Log4j是一个广泛使用的Java日志框架,在服务器端和桌面应用中非常常见。不过,Log4j原生并不直接支持Android平台,因为它依赖于一些Android系统不包含的库。但有一些开发者社区提供了对Android的适配版本,让Log4j...
Log4net是一个强大的日志管理框架,广泛应用于各种软件项目中,主要用于诊断和修复配置问题。该框架提供了丰富的功能,确保开发人员能够有效地记录、管理和分析应用中的日志信息。 **日志分级功能**是Log4net的核心...
### 日志框架总结:JUL、Log4j、Log4j2、Logback及门面技术 ...而对于复杂的企业级应用,则可能需要考虑使用更加强大和灵活的日志框架如Logback或Log4j2,并结合日志门面技术SLF4j来进一步增强系统的可维护性和扩展性。
在JAVA中,日志框架可以分为两种:日志抽象/门面和日志实现。日志抽象/门面负责定义了一套统一的日志打印标准,如Logger对象、Level对象,不负责具体的日志打印,如输出到文件、配置日志内容格式等。slf4j(Simple ...
在Android开发中,日志(Log)是调试和分析应用行为的重要工具。通常,开发者会使用Android提供的`Log`类来记录程序运行时的信息。然而,对于复杂的问题,仅依赖于IDE中的日志查看器可能不够,特别是当需要长期跟踪...
此压缩包提供的资源是针对Tomcat8及其以下版本的日志管理解决方案,主要涉及Log4j这个流行的Java日志框架。下面将详细介绍如何在Tomcat8中替换或更新Log4j来记录日志。 首先,让我们了解一下Log4j。Log4j是Apache...
在Android开发中,自定义日志框架是一种常见的实践,它可以帮助开发者更好地监控应用程序的运行状态,定位和解决问题。本文将详细介绍如何在Android环境下构建自己的日志框架,以及这样做的好处。 首先,Android...
Java日志框架是Java开发中不可或缺的一部分,它用于记录应用程序运行过程中的各种信息,帮助开发者在出现问题时进行调试和分析。日志框架的选择和整合对于一个项目来说至关重要,因为它不仅影响到开发效率,还直接...
在IT行业中,日志记录是调试和监控应用程序的关键部分,特别是对于Java开发者而言,Log4j是一个非常常用的日志框架。当我们遇到“无法打出log4j日志的问题”,这通常是由于配置、环境或代码实现中的某些错误导致的。...
Commons Logging的主要目标是解耦应用程序与特定的日志实现之间的依赖,这样可以在运行时动态切换日志框架,如log4j或java.util.logging。尽管如此,Commons Logging自身并不提供实际的日志记录功能,它只是一个接口...
在IT行业中,日志(log)是至...综上所述,"log日志的实现"涉及了如何在Struts和iBatis等框架中配置和使用日志,以及如何通过最佳实践来提升日志的价值。通过对日志的合理管理,可以大大提高开发效率和系统的可维护性。
7. **多线程安全**:在Android多线程环境中,日志框架需要确保线程安全,避免并发问题。 实现自定义日志框架时,可以创建一个`Logger`类,包含上述各种日志级别方法,并在其中实现日志输出的逻辑。例如: ```java ...
Log4j是Apache组织开发的一个开源日志框架,它是Java日志处理领域的经典工具,因其高效、灵活和可扩展性而广受欢迎。 **一、Log4j的基本概念** 1. **Logger(日志器)**:日志的主体,用于创建和管理日志记录。每...
**log4cplus** 是一个基于C++的开源日志框架,它的设计灵感来源于Java社区中的log4j,旨在提供一种高效、灵活且易于使用的日志记录解决方案。这个框架允许开发者在C++程序中方便地记录调试信息,帮助追踪代码问题、...