问题:
(一)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
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