• slf4j


    后续要做个日志相关的东西,先笔记一下。

    slf4j是日志框架的一个门面端,背后实现者有log4j,logback等等。

    如何实现这个门面的呢?

    一般我们使用的代码如下:

    private static final Logger logger = LoggerFactory.getLogger(JSPCashierController.class);

    slf4j 的LoggerFactory具体实现了门面模式中对接各种实现的事情。

    public static Logger getLogger(Class<?> clazz) {
            Logger logger = getLogger(clazz.getName());
            if (DETECT_LOGGER_NAME_MISMATCH) {
                Class<?> autoComputedCallingClass = Util.getCallingClass();
                if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                    Util.report(String.format("Detected logger name mismatch. Given name: "%s"; computed name: "%s".", logger.getName(),
                                    autoComputedCallingClass.getName()));
                    Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
                }
            }
            return logger;
        }
        
         public static Logger getLogger(String name) {
            ILoggerFactory iLoggerFactory = getILoggerFactory();
            return iLoggerFactory.getLogger(name);
        }

    getILoggerFactory方法:

    public static ILoggerFactory getILoggerFactory() {
            if (INITIALIZATION_STATE == UNINITIALIZED) {
              // 防线程并发
                synchronized (LoggerFactory.class) {
                    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://jira.qos.ch/browse/SLF4J-97
                return SUBST_FACTORY;
            }
            throw new IllegalStateException("Unreachable code");
        }

    上面,注意到一个细节,就是在getILoggerFactory是做了线程安全操作的,我看的版本是1.7.21。而在1.7.7的版本上的代码如下:是没有做线程安全的的事情的。

    不过我也不知道啥原因,不深究了 哈哈。

    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");
      }

    结下来看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
          // 这里绑定的实例抽象,我们获取或设置所有logger相关信息都是通过它实现
          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方法:

    // 就是在classpath里找这个class,所以那些实现者比如log4j,logback,包里必然有这个路径下的class文件。
    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;
    }
    关于打日志(来自官方文档):
    如果日志打印级别是info,字符串拼接就成了不必要的消耗。
    logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    推荐下面写法,如果日志打印级别是debug,那么就会比上面的写法多一个判断的消耗。但是相对于拼接字符串打印日志来说可以忽略不计。
    if(logger.isDebugEnabled()) {
      logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
    }

    而在一个方法中有多处 logger.isDebugEnabled() 的判断,建议先获取好,然后再各个判断处使用,这样只要获取一次。

     
  • 相关阅读:
    Privacy & Logic
    Rules of Evidence
    Court terms & Judicial opinions
    Objections in Court
    US Trial Procedures
    Jeremy Jaynes v. Va.
    C++\CLI编程(一、命名空间)
    C++\CLI编程(一、命名空间)
    C++关于#include 两种 引用方式
    C++关于#include 两种 引用方式
  • 原文地址:https://www.cnblogs.com/killbug/p/6721047.html
Copyright © 2020-2023  润新知