自己动手写一个可以让slf4j加载的日志系统

问题:
(一)slf4j采用什么设计模式实现的?
(二)slf4j是如何加载log4j或logback日志实现框架的?
(三)如果自己实现一个日志系统,如何让sfl4j能够加载该日志系统?
一段典型slf4j日志实例化代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogMain {
        public static void main(String[] args ) {
               // TODO Auto-generated method stub
              Logger xLogger = LoggerFactory. getLogger (LogMain. class );
               xLogger .debug( "hello" );
       }
}

寻根问底,看看slf4j的Logger代码:
public interface Logger {
    /**
     * Case insensitive String constant used to retrieve the name of the root logger.
     *
     * @since 1.3
     */
    final public String ROOT_LOGGER_NAME = "ROOT" ;
    /**
     * Return the name of this <code> Logger </code> instance.
     * @return name of this logger instance
     */
    public String getName();
    /**
     * Is the logger instance enabled for the TRACE level?
     *
     * @return True if this Logger is enabled for the TRACE level,
     *         false otherwise.
     * @since 1.4
     */
    public boolean isTraceEnabled();
    /**
     * Log a message at the TRACE level.
     *
     * @param msg the message string to be logged
     * @since 1.4
     */
    public void trace(String msg );
//省略若干代码
}
查看 LoggerFactory代码:
public final class LoggerFactory {
private LoggerFactory () {
    }
    /**
     * Force LoggerFactory to consider itself uninitialized.
     * <p/>
     * <p/>
     * This method is intended to be called by classes (in the same package) for
     * testing purposes. This method is internal. It can be modified, renamed or
     * removed at any time without notice.
     * <p/>
     * <p/>
     * You are strongly discouraged from calling this method in production code.
     */
    static void reset() {
        INITIALIZATION_STATE = UNINITIALIZED ;
    }
    private final static void performInitialization() {
        bind ();
        if ( INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION ) {
            versionSanityCheck ();
        }
    }
private final static void bind() {
        try {
            Set<URL> staticLoggerBinderPathSet = null ;
            // skip check under android, see also
            // http://jira.qos.ch/browse/SLF4J-328
            if (! isAndroid ()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet ();
                reportMultipleBindingAmbiguity ( staticLoggerBinderPathSet );
            }
            // the next line does the binding
            StaticLoggerBinder. getSingleton ();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION ;
            reportActualBinding ( staticLoggerBinderPathSet );
            fixSubstituteLoggers ();
            replayEvents ();
            // release all resources in SUBST_FACTORY
            SUBST_FACTORY .clear();
        } 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 .contains( "org.slf4j.impl.StaticLoggerBinder.getSingleton()" )) {
                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 );
        }
    }
/**
     * 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 );
    }
    /**
     * Return a logger named corresponding to the class passed as parameter,
     * using the statically bound {@link ILoggerFactory} instance.
     *
     * <p>
     * In case the the <code> clazz </code> parameter differs from the name of the
     * caller as computed internally by SLF4J, a logger name mismatch warning
     * will be printed but only if the
     * <code> slf4j.detectLoggerNameMismatch </code> system property is set to
     * true. By default, this property is not set and no warnings will be
     * printed even in case of a logger name mismatch.
     *
     * @param clazz
     *            the returned logger will be named after clazz
     * @return logger
     *
     *
     * @see <a
     *      href="http://www.slf4j.org/codes.html#loggerNameMismatch">Detected
     *      logger name mismatch </a>
     */
    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 ;
    }
/**
     * 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 ) {
            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" );
    }
}
slf4j实例化流程图:

代码核心:StaticLoggerBinder
结论:要让slf4j加载自己实现的日志系统,我们自己的日志系统需要实现StaticLoggerBinder的getLoggerFactory接口。

开始实现我们自己的日志系统:
-step1 新建一个工程xfli.fastlog
-step2 新建一个包org.slf4j.impl
-step3 在org.slf4j.impl新建StaticLoggerBinder类,该类实现org.slf4j.spi.LoggerFactoryBinder接口
-step4 实现getLoggerFactory接口,返回LoggerContext
-step5 新建LoggerContext类,该类实现org.slf4j.ILoggerFactory接口
-step6 实现getLogger接口,返回我们自己实现的日志类实例即可
-step7 写一个main,测试我们的类是否能工作
-step8 打完收工

工程xfli.fastlog需要引入slf4j的maven包,参考:
< dependency >
      < groupId > org.slf4j </ groupId >
      < artifactId > slf4j- api </ artifactId >
      < version >1.7.7 </ version >
      < scope > compile </ scope >
    </ dependency >
    < dependency >
      < groupId > org.slf4j </ groupId >
      < artifactId > slf4j- ext </ artifactId >
      < version >1.7.7 </ version >
      < scope > test </ scope >
    </ dependency >
一个示例,请移步GitHub: https://github.com/cjjxfli/xfli.fastlog 

猜你喜欢

转载自blog.csdn.net/lxf20054658/article/details/80003302