[Java基础] 3、java.util.logging的Logger的使用原理

1、测试代码

package log.JDKLog;

import java.util.logging.Logger;

public class Test {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger("LogDemo");
        logger.info("第一次使用");
        logger.warning("第一次使用");
    }
}

2、使用原理

2.1、Logger.getLogger

	Logger.getLogger调用LogManager.demandLogger方法。
	首先获取LogManger.manger单例。然后SecurityManager进行安全检查(默认关闭)。
	@CallerSensitive
    public static Logger getLogger(String name) {
        // This method is intentionally not a wrapper around a call
        // to getLogger(name, resourceBundleName). If it were then
        // this sequence:
        //
        //     getLogger("Foo", "resourceBundleForFoo");
        //     getLogger("Foo");
        //
        // would throw an IllegalArgumentException in the second call
        // because the wrapper would result in an attempt to replace
        // the existing "resourceBundleForFoo" with null.
        return demandLogger(name, null, Reflection.getCallerClass());
    }

	private static Logger demandLogger(String name, String resourceBundleName, 
											Class<?> caller) {
        LogManager manager = LogManager.getLogManager();
        SecurityManager sm = System.getSecurityManager();
        if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
            if (caller.getClassLoader() == null) {
                return manager.demandSystemLogger(name, resourceBundleName);
            }
        }
        return manager.demandLogger(name, resourceBundleName, caller);
        // ends up calling new Logger(name, resourceBundleName, caller)
        // iff the logger doesn't exist already
    }

2.2、LogManager.getLogManager()获取LogManager.manager。

	LogManager.manager可能通过静态代码块初始化。
	在静态代码块中执行特权方法,就是当SecurityManager启动时不检查权限直接可以运行的代码。
	但是静态代码块中获取System.getProperty("java.util.logging.manager"),默认没有这个配置。
	所以静态代码块默认情况下不初始化LogManager.manager。
	LogManager.manager的默认初始化使用manager.ensureLogManagerInitialized();
在其中加载Propertieshe,rootLogger。
	// 静态代码块
	static {
        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
            @Override
            public LogManager run() {
                LogManager mgr = null;
                String cname = null;
                try {
                    cname = System.getProperty("java.util.logging.manager"); // 默认时没有配置
                    if (cname != null) {
                        try {
                            Class<?> clz = ClassLoader.getSystemClassLoader()
                                    .loadClass(cname);
                            mgr = (LogManager) clz.newInstance();
                        } catch (ClassNotFoundException ex) {
                            Class<?> clz = Thread.currentThread()
                                    .getContextClassLoader().loadClass(cname);
                            mgr = (LogManager) clz.newInstance();
                        }
                    }
                } catch (Exception ex) {
                    System.err.println("Could not load Logmanager \"" + cname + "\"");
                    ex.printStackTrace();
                }
                if (mgr == null) {
                    mgr = new LogManager();
                }
                return mgr;

            }
        });
    }
	
	// 获取LogManager单例
	public static LogManager getLogManager() {
        if (manager != null) { // 可能通过静态代码块初始化manager,默认不通过静态代码块加载
            manager.ensureLogManagerInitialized();
        }
        return manager;
    }

	// 确保日志管理器初始化完成
	final void ensureLogManagerInitialized() {
        final LogManager owner = this;
        if (initializationDone || owner != manager) {
            // we don't want to do this twice, and we don't want to do
            // this on private manager instances.
            return;
        }

        // Maybe another thread has called ensureLogManagerInitialized()
        // before us and is still executing it. If so we will block until
        // the log manager has finished initialized, then acquire the monitor,
        // notice that initializationDone is now true and return.
        // Otherwise - we have come here first! We will acquire the monitor,
        // see that initializationDone is still false, and perform the
        // initialization.
        //
        synchronized(this) {
            // If initializedCalled is true it means that we're already in
            // the process of initializing the LogManager in this thread.
            // There has been a recursive call to ensureLogManagerInitialized().
            final boolean isRecursiveInitialization = (initializedCalled == true);

            assert initializedCalled || !initializationDone
                    : "Initialization can't be done if initialized has not been called!";

            if (isRecursiveInitialization || initializationDone) {
                // If isRecursiveInitialization is true it means that we're
                // already in the process of initializing the LogManager in
                // this thread. There has been a recursive call to
                // ensureLogManagerInitialized(). We should not proceed as
                // it would lead to infinite recursion.
                //
                // If initializationDone is true then it means the manager
                // has finished initializing; just return: we're done.
                return;
            }
            // Calling addLogger below will in turn call requiresDefaultLogger()
            // which will call ensureLogManagerInitialized().
            // We use initializedCalled to break the recursion.
            initializedCalled = true;
            try {
                AccessController.doPrivileged(new PrivilegedAction<Object>() { // 特权执行
                    @Override
                    public Object run() {
                        assert rootLogger == null;
                        assert initializedCalled && !initializationDone;

                        // Read configuration.
                        owner.readPrimordialConfiguration(); // 加载了Properties

                        // Create and retain Logger for the root of the namespace.
                        owner.rootLogger = owner.new RootLogger(); // 创建根级别的Logger
                        owner.addLogger(owner.rootLogger);
                        if (!owner.rootLogger.isLevelInitialized()) {
                            owner.rootLogger.setLevel(defaultLevel);
                        }

                        // Adding the global Logger.
                        // Do not call Logger.getGlobal() here as this might trigger
                        // subtle inter-dependency issues.
                        @SuppressWarnings("deprecation")
                        final Logger global = Logger.global;

                        // Make sure the global logger will be registered in the
                        // global manager
                        owner.addLogger(global);
                        return null;
                    }
                });
            } finally {
                initializationDone = true;
            }
        }
    }

2.3、LogManager.demandLogger

	在LogManager.demandLogger方法中,首先从LogManager.userContext中查询
是否有该name的Logger,没有的话,则新建一个Logger。
	Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
        Logger result = getLogger(name);
        if (result == null) {
            // only allocate the new logger once
            Logger newLogger = new Logger(name, resourceBundleName, 
            									caller, this, false);
            do {
                if (addLogger(newLogger)) { // addLogger时设置Logger的parent
                    // We successfully added the new Logger that we
                    // created above so return it without refetching.
                    return newLogger;
                }

                // We didn't add the new Logger that we created above
                // because another thread added a Logger with the same
                // name after our null check above and before our call
                // to addLogger(). We have to refetch the Logger because
                // addLogger() returns a boolean instead of the Logger
                // reference itself. However, if the thread that created
                // the other Logger is not holding a strong reference to
                // the other Logger, then it is possible for the other
                // Logger to be GC'ed after we saw it in addLogger() and
                // before we can refetch it. If it has been GC'ed then
                // we'll just loop around and try again.
                result = getLogger(name);
            } while (result == null);
        }
        return result;
    }

2.4、LoggerContext.addLocalLogger

	将新建Logger添加到LoggerManager.userContext中。此步还将设置待添加Logger的parent。
	public boolean addLogger(Logger logger) {
        final String name = logger.getName();
        if (name == null) {
            throw new NullPointerException();
        }
        drainLoggerRefQueueBounded();
        LoggerContext cx = getUserContext();
        if (cx.addLocalLogger(logger)) { // 给logger添加parent
            // Do we have a per logger handler too?
            // Note: this will add a 200ms penalty
            loadLoggerHandlers(logger, name, name + ".handlers");
            return true;
        } else {
            return false;
        }
    }

2.5、Logger.info的使用

	logger.info("第一次使用")将调用logger中的handlers处理,如果没有则调用logger.parent
的handlers。默认的logger.parent为LoggerManager.rootLogger;里面有ConsoleHandler。
	// 调用info方法
	public void info(String msg) {
        log(Level.INFO, msg);
    }

	public void log(Level level, String msg) {
        if (!isLoggable(level)) {
            return;
        }
        // 日记记录,记录日记级别,信息,时间等
        LogRecord lr = new LogRecord(level, msg);
        doLog(lr);
    }
	
	private void doLog(LogRecord lr) {
        lr.setLoggerName(name);
        final LoggerBundle lb = getEffectiveLoggerBundle();
        final ResourceBundle  bundle = lb.userBundle;
        final String ebname = lb.resourceBundleName;
        if (ebname != null && bundle != null) {
            lr.setResourceBundleName(ebname);
            lr.setResourceBundle(bundle);
        }
        log(lr);
    }
	
	// 日记记录的处理
	public void log(LogRecord record) {
        if (!isLoggable(record.getLevel())) {
            return;
        }
        Filter theFilter = filter;
        if (theFilter != null && !theFilter.isLoggable(record)) {
            return;
        }

        // Post the LogRecord to all our Handlers, and then to
        // our parents' handlers, all the way up the tree.
		// 获取当前logger,获取其handlers。
		// 我们创建的Logger没有handles,所以遍历其parent。
		// 我们创建的Logger的parent为LogManager.RootLogger,它在调用时首先
		//initializeGlobalHandlers(),为其初始化全局处理器。默认为Logger.props
		//中"handlers -> java.util.logging.ConsoleHandler"。
        Logger logger = this;
        while (logger != null) {
            final Handler[] loggerHandlers = isSystemLogger
                ? logger.accessCheckedHandlers()
                : logger.getHandlers();

            for (Handler handler : loggerHandlers) {
                handler.publish(record);
            }

            final boolean useParentHdls = isSystemLogger
                ? logger.useParentHandlers
                : logger.getUseParentHandlers();

            if (!useParentHdls) {
                break;
            }

            logger = isSystemLogger ? logger.parent : logger.getParent();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥牛火锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值