目录
一.Java常用的日志框架介绍
二.Java常用日志框架分析
2.1 JUL使用
2.2Log4j使用
1.添加依赖
2.在classpath下面添加配置文件:log4j.properties
3.使用Log4j记录日志
2.3JCL使用分析
2.4SLF4J(酸辣粉4斤)
介绍(引用官网)
SLF4J绑定器
Spring4和Spring5的日志区别
Spring4的日志体系
Spring5的日志分析
小结:
日志作为项目系统记录关键节点信息的重要工具,相信大多数程序猿开发中都使用过不同类型的日志框架,而Java的日志框架五花八门,各有千秋,接下来就让我们慢慢来揭开这些花里胡哨的日志框架。
使用很简单,可以看到在控制台输出了日志信息(记录到文件的操作需要自己写文件追加实现,这里不演示),需要注意的是看此时的Logger是java.util.logging.Logger。
### 设置###
log4j.rootLogger = debug,stdout
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
我们发现JUL和Log4j都可以实现将日志输出到控制台(文件),姑且将这种类型称之为日志框架的实现者。
1.引入JCL依赖,项目依赖如下:
commons-logging
commons-logging
1.2
log4j
log4j
1.2.17
使用JCL记录日志
好吧 怀疑是Log4j在捣鬼,那么我将Log4j依赖删除然后我们只引入JCL,不引入其他任何依赖
commons-logging
commons-logging
1.2
再跑起来试试
等等,为毛这段日志这么熟悉。。。这不就是前面的JUL的日志信息嘛,不过换了个马甲。难道JCL没有自己的实现,只是个日志的中间商?我们跟着源码去瞅一瞅究竟。
Log log = LogFactory.getLog("JCL");//点击getLog跟进去看看
//就是下面这一段
public static Log getLog(String name) throws LogConfigurationException {
return getFactory().getInstance(name);
}
//再进去getInstance()
public Log getInstance(String name) throws LogConfigurationException {
Log instance = (Log) instances.get(name);
if (instance == null) {
instance = newInstance(name);
instances.put(name, instance);
}
return instance;
}
//再进去newInstance()
protected Log newInstance(String name) throws LogConfigurationException {
Log instance;
try {
if (logConstructor == null) {
instance = discoverLogImplementation(name);
}
else {
Object params[] = { name };
instance = (Log) logConstructor.newInstance(params);
}
if (logMethod != null) {
Object params[] = { this };
logMethod.invoke(instance, params);
}
return instance;
} catch (LogConfigurationException lce) {
throw lce;
} catch (InvocationTargetException e) {
Throwable c = e.getTargetException();
throw new LogConfigurationException(c == null ? e : c);
} catch (Throwable t) {
throw new LogConfigurationException(t);
}
}
重点来了
在方法discoverLogImplementation内存在上面这么一段代码,像是在重复加载类,掀开classesToDiscover的盖头:
原来按照JCL按照自己定义的顺序去依次判定能否加载Log4j,JUL,加载成功则退出循环,返回找到的日志对象,JCL还真的是个中间商。
给个图描绘一下JCL的思想
大致意思就是说酸辣粉是一款用于市面上各种日志框架的的一种抽象思像,借助于JCL的中间商原理,他比JCL更强大,可以适配几乎所有的日志实现,可以让用户更好的选择使用具体的日志框架。很重要的一点,就是建议用户在使用之前阅读一下使用手册
启用SLF4J只需要添加一个强制依赖slf4j-api
来吧,实战,去掉其他依赖,只加入slf4j-api
org.slf4j
slf4j-api
1.7.25
http://www.slf4j.org/codes.html#StaticLoggerBinder
官网的意思,大致是具体使用日志输出,还需要使用一个具体的日志的绑定器,绑定使用具体的日志框架。
SLF4J支持各种日志框架。 SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件,每个绑定对应一个支持的框架
来吧选择官方说的log4j的绑定器slf4j-log4j12
org.slf4j
slf4j-api
1.7.25
org.slf4j
slf4j-log4j12
1.7.25
果然,思想和JCL有点点类似,但是感觉酸辣粉更强大啊,扩展性更高。
//引入Spring4 灭有其他任何依赖
org.springframework
spring-context
4.3.8.RELEASE
进入方法查看日志是否是JUL
查看Spring4的依赖树:
结论:Spring4使用的是 JCL的日志体系
那么在Spring4下加入Log4j的依赖和配置文件,将使用Log4j记录日志。
新建一个Spring5项目
org.springframework
spring-context
5.1.3.RELEASE
无日志输出,同样 查看Sping5的依赖树
发现仍然是JCL框架,不过名字被修改成了spring-jcl,猜想是Spring自己改造后的jcl,进入类AbstractApplicationContext查看Logger的实例化
进入工厂方法LogFactory.getLog()
//1.LogFactory.getLog(Class clazz)
public static Log getLog(Class> clazz) {
return getLog(clazz.getName());
}
//2.getLog(String name)
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
//3.点击LogAdapter.createLog
public static Log createLog(String name) {
switch(logApi) {
case LOG4J:
return LogAdapter.Log4jAdapter.createLog(name);
case SLF4J_LAL:
return LogAdapter.Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return LogAdapter.Slf4jAdapter.createLog(name);
default:
return LogAdapter.JavaUtilAdapter.createLog(name);
}
}
//4.查看logApi何时赋值 ----静态构造块中
static {
logApi = LogAdapter.LogApi.JUL;
ClassLoader cl = LogAdapter.class.getClassLoader();
try {
Class.forName("org.apache.logging.log4j.spi.ExtendedLogger", false, cl);
logApi = LogAdapter.LogApi.LOG4J;
} catch (ClassNotFoundException var6) {
try {
Class.forName("org.slf4j.spi.LocationAwareLogger", false, cl);
logApi = LogAdapter.LogApi.SLF4J_LAL;
} catch (ClassNotFoundException var5) {
try {
Class.forName("org.slf4j.Logger", false, cl);
logApi = LogAdapter.LogApi.SLF4J;
} catch (ClassNotFoundException var4) {
;
}
}
}
}
直接赋值仍然是java.util.logging,然后尝试加载Log4j2,若能正常加载那么就是Log4j2,然后加载酸辣粉
引入Log4j2的依赖
org.springframework
spring-context
5.1.3.RELEASE
org.apache.logging.log4j
log4j-core
2.11.1
只是说缺少了Log4j2的配置文件
弄个Log4j2的配置文件
SLF4J的出现带来了许多灵活可配的日志方案,比如主流的slf4j+logback的日志记录方案,当我们在使用spring时,又想使用其他的日志方案,则需要将spring依赖的jcl排除
org.springframework
spring-core
commons-logging
commons-logging
${springframework.version}
如果有多个组件依赖了jcl,则需要各个剔除,操作比较复杂