├─java-log-impl # Java some log implementations(jul、log4j、log4j2、logback)
├─java-log-api-jcl # commons logging
├─java-log-api-slf4j # slf4j
└─log4j2-vulnerabilities # log4j2 CVE recurrence
- cd
log4j2-vulnerabilities
- run
com.itplh.log4j2.RmiServer
- run
com.itplh.log4j2.TestLog4j2UseJndi
-
Interface
- JCL(Apache Commons Logging)
- Slf4j
-
Implementation
- JUL(java.util.logging)
- log4j
- log4j2
- logback
- cd
java-log-api-jcl
- Run
com.itplh.jcl.TestCommonsLogging
, then observe console output - Adjust
org.apache.commons.logging.Log's
value incommons-logging.properties
, then rerun program and observe console output
Load implement class who org.apache.commons.logging.Log
, the bind log framework used it, invoke stack as follows:
Log log = LogFactory.getLog("jcl");
|- getLog:669, LogFactory (org.apache.commons.logging)
|- getInstance:292, LogFactoryImpl (org.apache.commons.logging.impl)
|- newInstance:541, LogFactoryImpl (org.apache.commons.logging.impl)
|- discoverLogImplementation:790, LogFactoryImpl (org.apache.commons.logging.impl)
|- createLogFromClass:960, LogFactoryImpl (org.apache.commons.logging.impl)
The whole process that commons-logging get Logger, details and summary as follows:
Get current thread of classloader, then classloader get LogFactroy from cache, that cache is WeakHashTable; if the cache exists it, return it, otherwise into next step;
Load commons-logging.properties that under classpath, judge use_tccl attribute, if it exists, then judge its value, if value is false, set baseClassLoader as current class classLoader;
Then get LogFactory, and has four ways:
(1)in system property find “org.apache.commons.logging.LogFactory” of value, then generate LogFactory;
(2)in resource “META-INF/services/org.apache.commons.logging.LogFactory” of value, then generate LogFactory;
(3)get “org.apache.commons.logging.LogFactory” of value from commons-logging.properties, then generate LogFactory;
(4)if none of the above successful, create default log factory:org.apache.commons.logging.impl.LogFactoryImpl
After get log factory is successfly, according to class name get Log instance;
The main logic is in discoverLogImplementation method:
(1)Check is exists “org.apache.commons.logging.Log” key in commons-logging.properties, create Log's implement class if this key exists, otherwise execute next logic;
(2)Traverse classesToDiscover array, this array saved Log's implement class full name and it contains four elements:org.apache.commons.logging.impl.Log4JLogger、org.apache.commons.logging.impl.Jdk14Logger、org.apache.commons.logging.impl.Jdk13LumberjackLogger、org.apache.commons.logging.impl.SimpleLog;
(3)Accroding to these full class name, load class file in order, then instantiates, final return Log's implementation.(Log's default implement class is Jdk14Logger.)
- cd
java-log-api-slf4j
- Run
com.itplh.slf4j.TestSlf4j
, then observe console output - Change slf4j's adaptor dependence relation where pom.xml, then rerun program and observe console out put
Load org.slf4j.impl.StaticLoggerBinder
from slf4j adaptor jar package, then bind log framework used it, invoke stack as follows:
Logger logger = LoggerFactory.getLogger("slf4j");
|- getLogger:362, LoggerFactory (org.slf4j)
|- getILoggerFactory:417, LoggerFactory (org.slf4j)
|- performInitialization:124, LoggerFactory (org.slf4j)
|- bind:146, LoggerFactory (org.slf4j)
|- findPossibleStaticLoggerBinderPathSet:301, LoggerFactory (org.slf4j)
If has multiple
org.slf4j.impl.StaticLoggerBinder
where classpath, final load one of these what depend on JVM class load mechanism.