maven 构建slf4j1.7.7之简单测试与源码解析

来源:互联网 发布:mac air 搜狗输入法 编辑:程序博客网 时间:2024/04/30 02:49

   参考:slf4j官网    http://www.slf4j.org/manual.html

好像说一个东西 都有描述的 额 

The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks, such as java.util.logging, logback and log4j. SLF4J allows the end-user to plug in the desired logging framework at deployment time. Note that SLF4J-enabling your library/application implies the addition of only a single mandatory dependency, namely slf4j-api-1.7.7.jar.


我英文也不好啊  估摸着  大致意思是 SLF4J类似于JDBC一样 是一个规范或者说是日志的抽象层 在底层可以使用常见的日志框架进行实现,如log4j、commons logging等

示意图




示意图就比较形象了 


  1、使用myeclipse 2013 构建maven工程,名为slf4j     此处有类似构建过程  http://blog.csdn.net/undergrowth/article/details/25241213

  修改 添加slf4j-log4j12的依赖  pom.xml 如下  

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.undergrowth</groupId><artifactId>slf4j</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>slf4j</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!-- 因为maven会处理slf4j-log4j12的传递依赖于slf4j-api --><!-- <dependency> --><!-- <groupId>org.slf4j</groupId> --><!-- <artifactId>slf4j-api</artifactId> --><!-- <version>1.7.7</version> --><!-- </dependency> --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.7</version></dependency><!-- 如果配置多个日志框架 谁在前 用谁 --><!-- <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.7.7</version> </dependency> --></dependencies></project>


 2、修改测试类 App.java

package com.undergrowth.slf4j;import java.util.Date;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Hello world! * */public class App {final static Logger logger=LoggerFactory.getLogger(App.class);    public static void main( String[] args )    {       //不带占位符    logger.debug("hello world");    //带占位符    logger.debug("hello world {} ,{}", "under", new Date());        }}

修改测试类 AppTest.java

package com.undergrowth.slf4j;import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;/** * Unit test for simple App. */public class AppTest     extends TestCase{    /**     * Create the test case     *     * @param testName name of the test case     */    public AppTest( String testName )    {        super( testName );    }    /**     * @return the suite of tests being tested     */    public static Test suite()    {        return new TestSuite( AppTest.class );    }    /**     * Rigourous Test :-)     */    public void testApp()    {    String[] testArgs={};        App.main(testArgs);    }}

测试testApp方法  运行结果

2014-九月-07 17:14:10 [main] DEBUG:  com.undergrowth.slf4j.App - hello world2014-九月-07 17:14:10 [main] DEBUG:  com.undergrowth.slf4j.App - hello world under ,Sun Sep 07 17:14:10 CST 2014


附 log4j.xml配置  :

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd"><log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"><!-- Appenders --><appender name="console" class="org.apache.log4j.ConsoleAppender"><param name="Target" value="System.out" /><layout class="org.apache.log4j.PatternLayout"><param name="ConversionPattern" value="%d{yyyy-MMM-dd HH:mm:ss} [%t] %-5p:  %c - %m%n" /></layout></appender><!-- Root Logger --><root><priority value="debug" /><appender-ref ref="console" /></root></log4j:configuration>

以上即是slf4j的的简单实例

3、查看slf4j的源码 简单解析其原理

   a:去github上clone 一份slf4j的源码  如下  

git clone https://github.com/qos-ch/slf4j.git
  b:新建工程,导入myeclipse ,正常导入后 如下

    


     可能问到的问题 参考 

   解决Maven报Plugin execution not covered by lifecycle configuration   http://blog.csdn.net/xxd851116/article/details/25197373

  c: 在上面的实例中 使用slf4j首先使用的是 org.slf4j.LoggerFactory.getLogger方法获取日志对象 查看getLogger()

   

/**   * Return a logger named corresponding to the class passed as parameter, using   * the statically bound {@link ILoggerFactory} instance.   *   * @param clazz the returned logger will be named after clazz   * @return logger   */  public static Logger getLogger(Class clazz) {    return getLogger(clazz.getName());  }

  /**   * Return a logger named according to the name parameter using the statically   * bound {@link ILoggerFactory} instance.   *   * @param name The name of the logger.   * @return logger   */  public static Logger getLogger(String name) {    ILoggerFactory iLoggerFactory = getILoggerFactory();    return iLoggerFactory.getLogger(name);  }

        看到调用了 getILoggerFactory()方法    查看

/**   * Return the {@link ILoggerFactory} instance in use.   * <p/>   * <p/>   * ILoggerFactory instance is bound with this class at compile time.   *   * @return the ILoggerFactory instance in use   */  public static ILoggerFactory getILoggerFactory() {    if (INITIALIZATION_STATE == UNINITIALIZED) {      INITIALIZATION_STATE = ONGOING_INITIALIZATION;      performInitialization();    }    switch (INITIALIZATION_STATE) {      case SUCCESSFUL_INITIALIZATION:        return StaticLoggerBinder.getSingleton().getLoggerFactory();      case NOP_FALLBACK_INITIALIZATION:        return NOP_FALLBACK_FACTORY;      case FAILED_INITIALIZATION:        throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);      case ONGOING_INITIALIZATION:        // support re-entrant behavior.        // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106        return TEMP_FACTORY;    }    throw new IllegalStateException("Unreachable code");  }

在该方法的注释中  很明确的有一行    我英文也不是很好  猜测 大致意思就是ILoggerFactory的实例对象绑定是在编译的时候决定的  这么绕呢

ILoggerFactory instance is bound with this class at compile time.

那就是说在编译的时候 ILoggerFactory这个接口  就指向了实际上实现它的子类上  

    看看ILoggerFacroty吧

    

/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free  of charge, to any person obtaining * a  copy  of this  software  and  associated  documentation files  (the * "Software"), to  deal in  the Software without  restriction, including * without limitation  the rights to  use, copy, modify,  merge, publish, * distribute,  sublicense, and/or sell  copies of  the Software,  and to * permit persons to whom the Software  is furnished to do so, subject to * the following conditions: * * The  above  copyright  notice  and  this permission  notice  shall  be * included in all copies or substantial portions of the Software. * * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND, * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */package org.slf4j;/** * <code>ILoggerFactory</code> instances manufacture {@link Logger} * instances by name. *  * <p>Most users retrieve {@link Logger} instances through the static * {@link LoggerFactory#getLogger(String)} method. An instance of of this * interface is bound internally with {@link LoggerFactory} class at  * compile time.  *  * @author Ceki Gülcü */public interface ILoggerFactory {    /**   * Return an appropriate {@link Logger} instance as specified by the   * <code>name</code> parameter.   *    * <p>If the name parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, that is    * the string value "ROOT" (case insensitive), then the root logger of the    * underlying logging system is returned.   *    * <p>Null-valued name arguments are considered invalid.   *   * <p>Certain extremely simple logging systems, e.g. NOP, may always   * return the same logger instance regardless of the requested name.   *    * @param name the name of the Logger to return   * @return a Logger instance    */  public Logger getLogger(String name);}

恩 也就只有一个 getLogger方法 好吧  还是接着看上面的getILoggerFactory方法吧

  显示一个 if 判断

   

  if (INITIALIZATION_STATE == UNINITIALIZED) {      INITIALIZATION_STATE = ONGOING_INITIALIZATION;      performInitialization();    }

     很明显 第一次的话  肯定会执行  performInitialization(); 方法 查看

 

private final static void performInitialization() {    bind();    if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {      versionSanityCheck();    }  }

恩 bind();   接着看  

 private final static void bind() {    try {      Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();      reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);      // the next line does the binding      StaticLoggerBinder.getSingleton();      INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;      reportActualBinding(staticLoggerBinderPathSet);      fixSubstitutedLoggers();    } catch (NoClassDefFoundError ncde) {      String msg = ncde.getMessage();      if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {        INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;        Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");        Util.report("Defaulting to no-operation (NOP) logger implementation");        Util.report("See " + NO_STATICLOGGERBINDER_URL                + " for further details.");      } else {        failedBinding(ncde);        throw ncde;      }    } catch (java.lang.NoSuchMethodError nsme) {      String msg = nsme.getMessage();      if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {        INITIALIZATION_STATE = FAILED_INITIALIZATION;        Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");        Util.report("Your binding is version 1.5.5 or earlier.");        Util.report("Upgrade your binding to version 1.6.x.");      }      throw nsme;    } catch (Exception e) {      failedBinding(e);      throw new IllegalStateException("Unexpected initialization failure", e);    }  }

看到这个方法这么多 就知道是重头戏了啊

先是   findPossibleStaticLoggerBinderPathSet()  方法

// We need to use the name of the StaticLoggerBinder class, but we can't reference  // the class itself.  private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";  private static Set<URL> findPossibleStaticLoggerBinderPathSet() {    // use Set instead of list in order to deal with  bug #138    // LinkedHashSet appropriate here because it preserves insertion order during iteration    Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();    try {      ClassLoader loggerFactoryClassLoader = LoggerFactory.class              .getClassLoader();      Enumeration<URL> paths;      if (loggerFactoryClassLoader == null) {        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);      } else {        paths = loggerFactoryClassLoader                .getResources(STATIC_LOGGER_BINDER_PATH);      }      while (paths.hasMoreElements()) {        URL path = (URL) paths.nextElement();        staticLoggerBinderPathSet.add(path);      }    } catch (IOException ioe) {      Util.report("Error getting resources from path", ioe);    }    return staticLoggerBinderPathSet;  }


额  这么多 大致意思就是说 通过类加载器 获取到 org/slf4j/impl/StaticLoggerBinder.class  这个类的资源定位符  

    这里有一点 特别强调 也是我找了好久才找到的  你看  

         


  看到上面两张图 你会发现 slf4j-api里面 是有StaticLoggerBinder.java类的   log4j-12里面也是有 StaticLoggerBinder.java类的 那么按照道理来说 即使我在使用slf4j的时候不指定任何的实现日志框架  

findPossibleStaticLoggerBinderPathSet() 这个方法 是不是至少都有一个结果?

答案是否  原因在这



看到了吧  原来slf4j-api在打包成jar的时候 删除了 org.slf4j.impl下面的所有java包  这也是下面代码成立的基础  这里不搞清楚 下面代码没法看啊


  这里 我做过测试了  在上面的pom.xml 里面 我已经做了注释  有多个日志框架的时候 谁在前 用谁    (当然这里是 排除掉联合多个日志框架的情况)

这个 reportMultipleBindingAmbiguity方法呢 当你写了多个日志框架的时候 比如 你写了 log4j jcl 如上面的pom.xml中一样 人家就会友善的提醒你 你写了多个了  

  /**   * Prints a warning message on the console if multiple bindings were found on the class path.   * No reporting is done otherwise.   *   */  private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) {    if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {      Util.report("Class path contains multiple SLF4J bindings.");      Iterator<URL> iterator = staticLoggerBinderPathSet.iterator();      while (iterator.hasNext()) {        URL path = (URL) iterator.next();        Util.report("Found binding in [" + path + "]");      }      Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");    }  }

最重要的来了

 // the next line does the binding      StaticLoggerBinder.getSingleton();

在上面已经说过了 因为slf4j-api中的StaticLoggerBinder已经被删除了  所以当你配置了日志实现框架的的时候 比如上面pom.xml 中的log4j12的时候 此时获取到的字节码 就是slf4j-log4j12中的StaticLoggerBinder的字节码  那么slf4j-log4j12里面的StaticLoggerBinder代码 如下‘

/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free  of charge, to any person obtaining * a  copy  of this  software  and  associated  documentation files  (the * "Software"), to  deal in  the Software without  restriction, including * without limitation  the rights to  use, copy, modify,  merge, publish, * distribute,  sublicense, and/or sell  copies of  the Software,  and to * permit persons to whom the Software  is furnished to do so, subject to * the following conditions: * * The  above  copyright  notice  and  this permission  notice  shall  be * included in all copies or substantial portions of the Software. * * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND, * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */package org.slf4j.impl;import org.apache.log4j.Level;import org.slf4j.ILoggerFactory;import org.slf4j.LoggerFactory;import org.slf4j.helpers.Util;import org.slf4j.spi.LoggerFactoryBinder;/** * The binding of {@link LoggerFactory} class with an actual instance of * {@link ILoggerFactory} is performed using information returned by this class. *  * @author Ceki Gülcü */public class StaticLoggerBinder implements LoggerFactoryBinder {  /**   * The unique instance of this class.   *    */  private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();  /**   * Return the singleton of this class.   *    * @return the StaticLoggerBinder singleton   */  public static final StaticLoggerBinder getSingleton() {    return SINGLETON;  }  /**   * Declare the version of the SLF4J API this implementation is compiled   * against. The value of this field is usually modified with each release.   */  // to avoid constant folding by the compiler, this field must *not* be final  public static String REQUESTED_API_VERSION = "1.6.99"; // !final  private static final String loggerFactoryClassStr = Log4jLoggerFactory.class      .getName();  /**   * The ILoggerFactory instance returned by the {@link #getLoggerFactory}   * method should always be the same object   */  private final ILoggerFactory loggerFactory;  private StaticLoggerBinder() {    loggerFactory = new Log4jLoggerFactory();    try {      Level level = Level.TRACE;    } catch (NoSuchFieldError nsfe) {      Util          .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");    }  }  public ILoggerFactory getLoggerFactory() {    return loggerFactory;  }  public String getLoggerFactoryClassStr() {    return loggerFactoryClassStr;  }}


可以很清楚的看到 当使用 StaticLoggerBinder.getSingleton(); 的时候   使用的是单例模式  构建了一个StaticLoggerBinder对象  在它的构造函数里面构造了

Log4jLoggerFactory对象

源码

/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free  of charge, to any person obtaining * a  copy  of this  software  and  associated  documentation files  (the * "Software"), to  deal in  the Software without  restriction, including * without limitation  the rights to  use, copy, modify,  merge, publish, * distribute,  sublicense, and/or sell  copies of  the Software,  and to * permit persons to whom the Software  is furnished to do so, subject to * the following conditions: * * The  above  copyright  notice  and  this permission  notice  shall  be * included in all copies or substantial portions of the Software. * * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND, * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */package org.slf4j.impl;import java.util.HashMap;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ConcurrentMap;import org.apache.log4j.LogManager;import org.slf4j.ILoggerFactory;import org.slf4j.Logger;/** * Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning * the appropriate named {@link Log4jLoggerAdapter} instance. *  * @author Ceki Gülcü */public class Log4jLoggerFactory implements ILoggerFactory {  // key: name (String), value: a Log4jLoggerAdapter;  ConcurrentMap<String, Logger> loggerMap;  public Log4jLoggerFactory() {    loggerMap = new ConcurrentHashMap<String, Logger>();  }  /*   * (non-Javadoc)   *    * @see org.slf4j.ILoggerFactory#getLogger(java.lang.String)   */  public Logger getLogger(String name) {    Logger slf4jLogger = loggerMap.get(name);    if (slf4jLogger != null) {      return slf4jLogger;    } else {      org.apache.log4j.Logger log4jLogger;      if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))        log4jLogger = LogManager.getRootLogger();      else        log4jLogger = LogManager.getLogger(name);      Logger newInstance = new Log4jLoggerAdapter(log4jLogger);      Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);      return oldInstance == null ? newInstance : oldInstance;    }  }}

会看到  Log4jLoggerFactory 的构造函数 是构建了一个  // key: name (String), value: a Log4jLoggerAdapter;   存放适配器的哈希map


好  现在看起来 发现  还是没有最终的串联起来 因为还有一步就成功了啊

    

看上面 bind()方法里面  当

StaticLoggerBinder.getSingleton();      INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;

执行完后  初始化状态改为成功初始化 后面的就不说了 等此方法执行完后  回到 performInitialization()  再回到 getILoggerFactory()  看到有一个switch语句 

switch (INITIALIZATION_STATE) {      case SUCCESSFUL_INITIALIZATION:        return StaticLoggerBinder.getSingleton().getLoggerFactory();      case NOP_FALLBACK_INITIALIZATION:        return NOP_FALLBACK_FACTORY;      case FAILED_INITIALIZATION:        throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);      case ONGOING_INITIALIZATION:        // support re-entrant behavior.        // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106        return TEMP_FACTORY;    }

因为在bind()中 初始化状态为成功初始化 那么此时 这里即 执行  

return StaticLoggerBinder.getSingleton().getLoggerFactory();

上面说了  
StaticLoggerBinder.getSingleton()

的字节码为 slf4j-log4j12里面的StaticLoggerBinder  那么  即会调用  

 public ILoggerFactory getLoggerFactory() {    return loggerFactory;  }


返回在构造函数中创建的 Log4jLoggerFactory对象 (此对象也实现了ILoggerFactory接口)


待getILoggerFactory()  执行完 返回到 getLogger(String name)  执行  

 return iLoggerFactory.getLogger(name);

哦 这里不就是执行  Log4jLoggerFactory对象 的getLogger方法么  是啊 

  /*   * (non-Javadoc)   *    * @see org.slf4j.ILoggerFactory#getLogger(java.lang.String)   */  public Logger getLogger(String name) {    Logger slf4jLogger = loggerMap.get(name);    if (slf4jLogger != null) {      return slf4jLogger;    } else {      org.apache.log4j.Logger log4jLogger;      if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))        log4jLogger = LogManager.getRootLogger();      else        log4jLogger = LogManager.getLogger(name);      Logger newInstance = new Log4jLoggerAdapter(log4jLogger);      Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);      return oldInstance == null ? newInstance : oldInstance;    }  }

这里就是从map中按照名字查找 是否有相应的日志适配器 有的话 返回 没有的话 添加到map中 并返回 

接着 再返回到getLogger(Class clazz)   此时slf4j中才拿到了Logger对象 返回给

final static Logger logger=LoggerFactory.getLogger(App.class);
上层


那么slf4j的日志是怎么输出来的呢  刚才只是slf4j拿到Logger  其实  实现就是在 上面的适配器中  

Log4jLoggerAdapter

/** * Copyright (c) 2004-2011 QOS.ch * All rights reserved. * * Permission is hereby granted, free  of charge, to any person obtaining * a  copy  of this  software  and  associated  documentation files  (the * "Software"), to  deal in  the Software without  restriction, including * without limitation  the rights to  use, copy, modify,  merge, publish, * distribute,  sublicense, and/or sell  copies of  the Software,  and to * permit persons to whom the Software  is furnished to do so, subject to * the following conditions: * * The  above  copyright  notice  and  this permission  notice  shall  be * included in all copies or substantial portions of the Software. * * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND, * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */package org.slf4j.impl;import java.io.Serializable;import org.apache.log4j.Level;import org.slf4j.Logger;import org.slf4j.Marker;import org.slf4j.helpers.FormattingTuple;import org.slf4j.helpers.MarkerIgnoringBase;import org.slf4j.helpers.MessageFormatter;import org.slf4j.spi.LocationAwareLogger;/** * A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in * conforming to the {@link Logger} interface. *  * <p> * Note that the logging levels mentioned in this class refer to those defined * in the <a * href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/Level.html"> * <code>org.apache.log4j.Level</code></a> class. *  * <p> * The TRACE level was introduced in log4j version 1.2.12. In order to avoid * crashing the host application, in the case the log4j version in use predates * 1.2.12, the TRACE level will be mapped as DEBUG. See also <a * href="http://bugzilla.slf4j.org/show_bug.cgi?id=68">bug 68</a>. *  * @author Ceki Gülcü */public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements    LocationAwareLogger, Serializable {  private static final long serialVersionUID = 6182834493563598289L;  final transient org.apache.log4j.Logger logger;  /**   * Following the pattern discussed in pages 162 through 168 of "The complete   * log4j manual".   */  final static String FQCN = Log4jLoggerAdapter.class.getName();  // Does the log4j version in use recognize the TRACE level?  // The trace level was introduced in log4j 1.2.12.  final boolean traceCapable;  // WARN: Log4jLoggerAdapter constructor should have only package access so  // that  // only Log4jLoggerFactory be able to create one.  Log4jLoggerAdapter(org.apache.log4j.Logger logger) {    this.logger = logger;    this.name = logger.getName();    traceCapable = isTraceCapable();  }  private boolean isTraceCapable() {    try {      logger.isTraceEnabled();      return true;    } catch (NoSuchMethodError e) {      return false;    }  }  /**   * Is this logger instance enabled for the TRACE level?   *    * @return True if this Logger is enabled for level TRACE, false otherwise.   */  public boolean isTraceEnabled() {    if (traceCapable) {      return logger.isTraceEnabled();    } else {      return logger.isDebugEnabled();    }  }  /**   * Log a message object at level TRACE.   *    * @param msg   *          - the message object to be logged   */  public void trace(String msg) {    logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, null);  }  /**   * Log a message at level TRACE according to the specified format and   * argument.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for level TRACE.   * </p>   *    * @param format   *          the format string   * @param arg   *          the argument   */  public void trace(String format, Object arg) {    if (isTraceEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft          .getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level TRACE according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the TRACE level.   * </p>   *    * @param format   *          the format string   * @param arg1   *          the first argument   * @param arg2   *          the second argument   */  public void trace(String format, Object arg1, Object arg2) {    if (isTraceEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft          .getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level TRACE according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the TRACE level.   * </p>   *    * @param format   *          the format string   * @param arguments   *          an array of arguments   */  public void trace(String format, Object... arguments) {    if (isTraceEnabled()) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);      logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, ft          .getMessage(), ft.getThrowable());    }  }  /**   * Log an exception (throwable) at level TRACE with an accompanying message.   *    * @param msg   *          the message accompanying the exception   * @param t   *          the exception (throwable) to log   */  public void trace(String msg, Throwable t) {    logger.log(FQCN, traceCapable ? Level.TRACE : Level.DEBUG, msg, t);  }  /**   * Is this logger instance enabled for the DEBUG level?   *    * @return True if this Logger is enabled for level DEBUG, false otherwise.   */  public boolean isDebugEnabled() {    return logger.isDebugEnabled();  }  /**   * Log a message object at level DEBUG.   *    * @param msg   *          - the message object to be logged   */  public void debug(String msg) {    logger.log(FQCN, Level.DEBUG, msg, null);  }  /**   * Log a message at level DEBUG according to the specified format and   * argument.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for level DEBUG.   * </p>   *    * @param format   *          the format string   * @param arg   *          the argument   */  public void debug(String format, Object arg) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level DEBUG according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the DEBUG level.   * </p>   *    * @param format   *          the format string   * @param arg1   *          the first argument   * @param arg2   *          the second argument   */  public void debug(String format, Object arg1, Object arg2) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level DEBUG according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the DEBUG level.   * </p>   *    * @param format   *          the format string   * @param arguments an array of arguments   */  public void debug(String format, Object... arguments) {    if (logger.isDebugEnabled()) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);      logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log an exception (throwable) at level DEBUG with an accompanying message.   *    * @param msg   *          the message accompanying the exception   * @param t   *          the exception (throwable) to log   */  public void debug(String msg, Throwable t) {    logger.log(FQCN, Level.DEBUG, msg, t);  }  /**   * Is this logger instance enabled for the INFO level?   *    * @return True if this Logger is enabled for the INFO level, false otherwise.   */  public boolean isInfoEnabled() {    return logger.isInfoEnabled();  }  /**   * Log a message object at the INFO level.   *    * @param msg   *          - the message object to be logged   */  public void info(String msg) {    logger.log(FQCN, Level.INFO, msg, null);  }  /**   * Log a message at level INFO according to the specified format and argument.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the INFO level.   * </p>   *    * @param format   *          the format string   * @param arg   *          the argument   */  public void info(String format, Object arg) {    if (logger.isInfoEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at the INFO level according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the INFO level.   * </p>   *    * @param format   *          the format string   * @param arg1   *          the first argument   * @param arg2   *          the second argument   */  public void info(String format, Object arg1, Object arg2) {    if (logger.isInfoEnabled()) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level INFO according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the INFO level.   * </p>   *    * @param format   *          the format string   * @param argArray   *          an array of arguments   */  public void info(String format, Object... argArray) {    if (logger.isInfoEnabled()) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);      logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log an exception (throwable) at the INFO level with an accompanying   * message.   *    * @param msg   *          the message accompanying the exception   * @param t   *          the exception (throwable) to log   */  public void info(String msg, Throwable t) {    logger.log(FQCN, Level.INFO, msg, t);  }  /**   * Is this logger instance enabled for the WARN level?   *    * @return True if this Logger is enabled for the WARN level, false otherwise.   */  public boolean isWarnEnabled() {    return logger.isEnabledFor(Level.WARN);  }  /**   * Log a message object at the WARN level.   *    * @param msg   *          - the message object to be logged   */  public void warn(String msg) {    logger.log(FQCN, Level.WARN, msg, null);  }  /**   * Log a message at the WARN level according to the specified format and   * argument.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the WARN level.   * </p>   *    * @param format   *          the format string   * @param arg   *          the argument   */  public void warn(String format, Object arg) {    if (logger.isEnabledFor(Level.WARN)) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at the WARN level according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the WARN level.   * </p>   *    * @param format   *          the format string   * @param arg1   *          the first argument   * @param arg2   *          the second argument   */  public void warn(String format, Object arg1, Object arg2) {    if (logger.isEnabledFor(Level.WARN)) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level WARN according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the WARN level.   * </p>   *    * @param format   *          the format string   * @param argArray   *          an array of arguments   */  public void warn(String format, Object... argArray) {    if (logger.isEnabledFor(Level.WARN)) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);      logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log an exception (throwable) at the WARN level with an accompanying   * message.   *    * @param msg   *          the message accompanying the exception   * @param t   *          the exception (throwable) to log   */  public void warn(String msg, Throwable t) {    logger.log(FQCN, Level.WARN, msg, t);  }  /**   * Is this logger instance enabled for level ERROR?   *    * @return True if this Logger is enabled for level ERROR, false otherwise.   */  public boolean isErrorEnabled() {    return logger.isEnabledFor(Level.ERROR);  }  /**   * Log a message object at the ERROR level.   *    * @param msg   *          - the message object to be logged   */  public void error(String msg) {    logger.log(FQCN, Level.ERROR, msg, null);  }  /**   * Log a message at the ERROR level according to the specified format and   * argument.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the ERROR level.   * </p>   *    * @param format   *          the format string   * @param arg   *          the argument   */  public void error(String format, Object arg) {    if (logger.isEnabledFor(Level.ERROR)) {      FormattingTuple ft = MessageFormatter.format(format, arg);      logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at the ERROR level according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the ERROR level.   * </p>   *    * @param format   *          the format string   * @param arg1   *          the first argument   * @param arg2   *          the second argument   */  public void error(String format, Object arg1, Object arg2) {    if (logger.isEnabledFor(Level.ERROR)) {      FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);      logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log a message at level ERROR according to the specified format and   * arguments.   *    * <p>   * This form avoids superfluous object creation when the logger is disabled   * for the ERROR level.   * </p>   *    * @param format   *          the format string   * @param argArray   *          an array of arguments   */  public void error(String format, Object... argArray) {    if (logger.isEnabledFor(Level.ERROR)) {      FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);      logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());    }  }  /**   * Log an exception (throwable) at the ERROR level with an accompanying   * message.   *    * @param msg   *          the message accompanying the exception   * @param t   *          the exception (throwable) to log   */  public void error(String msg, Throwable t) {    logger.log(FQCN, Level.ERROR, msg, t);  }  public void log(Marker marker, String callerFQCN, int level, String msg,      Object[] argArray, Throwable t) {    Level log4jLevel;    switch (level) {    case LocationAwareLogger.TRACE_INT:      log4jLevel = traceCapable ? Level.TRACE : Level.DEBUG;      break;    case LocationAwareLogger.DEBUG_INT:      log4jLevel = Level.DEBUG;      break;    case LocationAwareLogger.INFO_INT:      log4jLevel = Level.INFO;      break;    case LocationAwareLogger.WARN_INT:      log4jLevel = Level.WARN;      break;    case LocationAwareLogger.ERROR_INT:      log4jLevel = Level.ERROR;      break;    default:      throw new IllegalStateException("Level number " + level          + " is not recognized.");    }    logger.log(callerFQCN, log4jLevel, msg, t);  }}


你会发现   在Logger中中有的方法 在这里一一都有对应   

 最终的输出 是通过 

org.apache.log4j.Logger
对于log4j12是这样的   jcl logging logback 原理 也应该都一样 


卡  终于写完了   。。。



0 0