文章目录
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();
}
}