为什么要使用slf4j和log4j2

1、多日志实现组件存在问题

java世界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过作为组件开发者,他们希望自己的组件不要紧紧依赖某一个工具,毕竟在同一个时候还有很多其他很多日志工具,假如一个应用程序用到了两个组件,恰好两个组件使用不同的日志工具,那么应用程序就会有两份日志输出了。

2、解决多日志实现组件问题,引入JCL

为了解决这个问题,Apache Commons Logging (之前叫 Jakarta Commons Logging,JCL)粉墨登场,JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只需要针对 JCL 接口开发,而调用组件的应用程序则可以在运行时搭配自己喜好的日志实践工具。

3、JCL引发的问题

所以即使到现在你仍会看到很多程序应用 JCL + log4j 这种搭配,不过当程序规模越来越庞大时,JCL的动态绑定并不是总能成功,在Sping官方文档中Not Using Commons Logging小节也提到因为算法问题引起,

4、解决JCL动态绑定引发的问题

解决方法之一就是在程序部署时静态绑定指定的日志工具,这就是 SLF4J 产生的原因。

跟 JCL 一样,SLF4J 也是只提供 log 接口,具体的实现是在打包应用程序时所放入的绑定器(名字为 slf4j-XXX-version.jar)来决定,XXX 可以是 log4j12, jdk14, logback, nop 等,他们实现了跟具体日志工具(比如 log4j)的绑定及代理工作。

举个例子:如果一个程序希望用 log4j 日志工具,那么程序只需针对 slf4j-api 接口编程,额外添加slf4j-log4j12-version.jar 和 log4j.jar 的依赖就可以了。

5、排除现有commons-logging依赖的影响

现在还有一个问题,假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你需要一个桥接器(名字为 jcl-over-slf4j.jar)把他们的日志输出重定向到 SLF4J

所谓的桥接器就是一个假的日志实现工具,比如当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即使某个组件原本是通过 JCL 输出日志的,现在却会被 jcl-over-slf4j “骗到”SLF4J 里,然后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。

过程如下:

Component(服务)
|
| log to Apache Commons Logging(JCL)
V
jcl-over-slf4j.jar — (redirect) —> SLF4j —> slf4j-log4j12-version.jar —> log4j.jar —> 输出日志

注意:如果使用了log4j实现slf4j,添加log4j-over-slf4j桥接器,结果就是log4j —> slf4j —> log4j,输出日志命令被踢来踢去,此时要么去掉log4j-over-slf4j桥接器,要么替换slf4j的实现,比如换成logback,否则陷入死循环(这种方式的使用场景是,项目中原来使用的是log4j日志,想要更改为logback,需要先用log4j-over-slf4j桥接到slf4j,然后slf4j再用logback作为日志的实现)

6、如何排除现有commons-logging依赖

①:maven项目,通过标签排除commons-logging依赖,这种方式的弊端是繁琐,不彻底,容易遗漏,说不定某个依赖就又把commons-logging引入了项目

      注意:如果在依赖中剔除了common-loggin包,但又不引入其他日志系统,则Spring会在启动的时候报如下错误:
      java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 

      参考:https://www.cnblogs.com/listentowinds/p/9131197.html

②:通过桥接的模式,添加该jar包,所有common-logging真正的实现将由jcl-over-slf4j提供,也就是由slf4j负责

参考地址:http://slf4j.org/faq.html#excludingJCL

<dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>2.0.0-alpha2-SNAPSHOT</version>
</dependency>

7.为什么要使用slf4j和log4j2

①:为什么选择slf4j

②:为什么选择Log4j2

参考文章:https://blog.csdn.net/lyf1548603225/article/details/97031857

https://blog.csdn.net/qq_32625839/article/details/80893550

  1. Log4j 2被设计成可用作审计日志框架。在重新配置时,Log4j 1.x和Logback都会丢失事件。Log4j 2不会。在Logback中,Appender中的异常永远不会对应用程序可见。 在Log4j中,可以将Appender配置为允许异常渗透到应用程序。
  2. Log4j 2包含基于LMAX Disruptor库的下一代异步日志记录器(Asynchronous Loggers)。 在多线程场景中,相比 Log4j 1.x和Logback ,异步日志记录器的吞吐量高10倍,延迟低几个数量级。
  3. Log4j 2对于独立应用程序是无垃圾的,对于稳态日志记录期间的Web应用程序是低垃圾。 这减少了垃圾收集器的压力,并提供更好的响应时间性能。

如何使用slf4j和Log4j2

1.导入jar包

<dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>2.0.0-alpha1</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.11.1</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.11.1</version>
</dependency>

jcl-over-slf4j: 将jcl日志桥接到slf4j

log4j-slf4j-impl :如果现有组件使用SLF4J,并且您希望将此日志记录路由到Log4j 2

上面两部分官方文档参考:

log4j2: https://logging.apache.org/log4j/2.x/maven-artifacts.html#Optional_Components(仔细看,肯定有)

slf4j: http://www.slf4j.org/manual.html

log4j-web:官方文档参考:https://logging.apache.org/log4j/2.x/manual/webapp.html

2.在classPath下添加 Log4j2.xml

(Log4j2.xml,Log4j2.properties,Log4j2.yaml,Log4j2.json都支持)

支持类型官方文档参考:http://logging.apache.org/log4j/2.x/manual/configuration.html#AutomaticConfiguration

xml内容官方文档参考:http://logging.apache.org/log4j/2.x/manual/configuration.html#ConfigurationSyntax

<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="1800"><!--变量配置 --><Properties><!-- 格式化输出:%date表示日期  %-5level什么级别的日志   %c代表已逗号分隔的包名展示几个   %msg日志内容   %n换行  --><property name="logPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %c{20} - %msg%n" /><!-- 定义日志存储的位置,不要配置相对路径 --><property name="folderUrl" value="${sys:catalina.home}/logs" /><!-- 备份文件数量 --><property name="backupsFileNum" value="31" /></Properties><Appenders><!-- 输出到控制台 --><Console name="stdout" target="SYSTEM_OUT"><PatternLayout pattern="${logPattern}" /><Filters><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/></Filters></Console><!-- 输出到文件中  fileName文件的名称   filePattern当文件备份时的路径和格式 --><RollingRandomAccessFile name="infoLevelLog" fileName="${folderUrl}/info.log"filePattern="${folderUrl}/$${date:yyyy-MM}/info/info-%d{yyyy-MM-dd}.log"><PatternLayout pattern="${logPattern}" /><Filters><!-- ThresholdFilter  level代表匹配大于等于该级别的日志,onMatch匹配到做什么, onMismatch没有匹配到做什么,三个值,ACCEPT 接受, DENY 拒绝, NEUTRAL 中立,即向下执行,在有多个过滤器的时候必须完全匹配才行--><ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><!-- modulate="true" (boolean)以0点为边界进行偏移计算 --><!-- interval="1" 表示将1天一个日志文件   和  filePattern 的日期格式有关,如果日期格式带有小时,就是以小时为单位,不然就是以天为单位 --><TimeBasedTriggeringPolicy modulate="true"  interval="1"/></Policies><!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了31 --><DefaultRolloverStrategy max="${backupsFileNum}"/></RollingRandomAccessFile><RollingRandomAccessFile name="warnLevelLog" fileName="${folderUrl}/warn.log"filePattern="${folderUrl}/$${date:yyyy-MM}/warn/warn-%d{yyyy-MM-dd}.log"><PatternLayout pattern="${logPattern}" /><Filters><ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/></Filters><Policies><TimeBasedTriggeringPolicy modulate="true"  interval="1"/></Policies><DefaultRolloverStrategy max="${backupsFileNum}"/></RollingRandomAccessFile><RollingRandomAccessFile name="errorLevelLog"  fileName="${folderUrl}/error.log"filePattern="${folderUrl}/$${date:yyyy-MM}/error/error-%d{yyyy-MM-dd}.log"><PatternLayout pattern="${logPattern}" /><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/><Policies><TimeBasedTriggeringPolicy modulate="true"  interval="1"/></Policies><DefaultRolloverStrategy max="${backupsFileNum}"/></RollingRandomAccessFile></Appenders><Loggers><logger name="cn.yuexiang365" level="info"  additivity="false"> <AppenderRef ref="infoLevelLog" /><AppenderRef ref="warnLevelLog" /><AppenderRef ref="errorLevelLog" /></logger><Root level="info"><AppenderRef ref="stdout" /><AppenderRef ref="warnLevelLog" /><AppenderRef ref="errorLevelLog" /></Root></Loggers>
</Configuration>

3.日志打印

获取日志对象的两种方式

private Log log = LogFactory.getLog(getClass());    //jcl
private Logger log = LoggerFactory.getLogger(xxx.class);    //slf4j

通过jcl获取的日志打印对象和slf4j获取的日志打印对象都是log4j2,因为已经通过jcl-over-slf4j将jcl桥接到slf4j了,slf4j获取的日志实现是log4j2,所以两者获取的日志对象实现类都是log4j2.

log.info("info");    //注意xml中设置的日志打印级别,如果高于该级别,通过该级别的打印就无法显示

问题锦集

配置失效导致spring等框架一直打印DEBUG级别的日志

在应用中使用了SpringMVC+hibernate+Log4j+SLF4J。Log4j的日志级别调到INFO。但是在web容器(Tomcat)在启动和运行的时候spring,Hibernate等框架中DEBUG级别的日志不断狂刷,导致日志文件剧增,磁盘没几天就爆了。

一直以为自己的Log4j配置文件写的有问题。后来在自己新搭建的project中发现Log4j的配置是正确的。只打印出INFO及以上级别的日志信息。后来才知道,是因为自己的应用依赖的jar隐式依赖了logback日志框架。

Log4j和logback是有冲突的,这样会导致Log4j的日志级别降低到DEBUG级别。知道了原因,就在maven依赖中把logback的隐式依赖给去掉。然后启动tomcat,发现日志可以正常打印。


log4j2 无法绑定到 SLF4J

SLF4J: No SLF4J providers were found.

pom.xml中添加的依赖有问题

   

官方文档解释:https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html


spring项目中使用slf4j和log4j2日志框架相关推荐

  1. Spring Boot + Log4j2 日志框架配置 (Maven)

    参考Spring Boot官方文档 日志部分 Spring Boot默认情况下,当使用"Starters" 使用Logback输出日志 , 还包括适当的Logback路由, 确保其 ...

  2. spring boot—集成log4j2日志框架

    文章目录 市场上的日志框架 spring boot日志框架关系 移除默认日志框架 切换为log4j2日志框架 市场上的日志框架   1)日志门面最常用的是slf4j   2)日志实现最常用的是logb ...

  3. 将MongoDB集成到您的Spring项目中

    本文展示了如何通过注释配置将MongoDB集成到您的spring项目中. 我们将从Gradle配置开始. group 'com.gkatzioura.spring' version '1.0-SNAP ...

  4. redis集成spring_将Redis集成到您的Spring项目中

    redis集成spring 本文介绍如何通过注释配置将Redis缓存集成到您的spring项目中. 我们将从Gradle配置开始. 我们将使用jedis驱动程序. group 'com.gkatzio ...

  5. 将Redis集成到您的Spring项目中

    本文展示了如何通过注释配置将Redis缓存集成到您的spring项目中. 我们将从Gradle配置开始. 我们将使用jedis驱动程序. group 'com.gkatzioura.spring' v ...

  6. java日志怎么实现_JAVA项目中怎么实现一个通用日志记录功能

    JAVA项目中怎么实现一个通用日志记录功能 发布时间:2020-11-21 17:04:50 来源:亿速云 阅读:53 作者:Leah 今天就跟大家聊聊有关JAVA项目中怎么实现一个通用日志记录功能, ...

  7. Log4j2日志框架集成Slf4j日志门面

    1.说明 本文介绍使用日志门面Slf4j打印日志, 底层日志实现使用Log4j2框架, 方便以后切换底层日志实现, Log4j2可以替换成Logback等. 2.依赖管理 在pom.xml依赖管理中导 ...

  8. spring 项目中集成 Protocol Buffers 示例

    http://blog.csdn.net/fangzhangsc2006/article/details/8687388 本文适用于了解spring框架,同时想在spring项目中使用Protocol ...

  9. 【SpringBoot】Spring项目中value注解,@Value不能够读取到配置文件的值,无法成功注入值的问题汇总及解决

    Spring项目中value注解,@Value不能够读取到配置文件的值,无法成功注入值的问题汇总及解决 @Value注解 常规用法示例 我们都知道通过@Value()注解可以取到我们配置文件的内容,之 ...

最新文章

  1. CSRF 攻击的应对之道--转
  2. SAP号码段表及相关操作T-CODE
  3. C++ edit distances最小编辑距离(附完整源码)
  4. linux ftp下载文件_Linux系统中10个使用Wget命令下载文件示例
  5. Leecode07. 整数反转——Leecode大厂热题100道系列
  6. SpringData_Repository接口概述
  7. android 关闭软键盘_实现边到边的体验 | 让您的软键盘动起来 (一)
  8. 【Vegas原创】巧用GridView ButtonField列
  9. 一个Linux驱动:Simple - REALLY simple memory mapping demonstration.
  10. Objective-C学习准备__C语言6
  11. 刷课在线支付系统(新手入门编写,大佬勿喷)
  12. 地心、南极、太平洋……那些年亚特兰蒂斯“去”过的地方
  13. 中国各省存贷款余额(2003-2020年)
  14. RFID固定资产定位管理系统-智慧资产人员可视化管理系统
  15. windows驱动ddk环境设置
  16. 一句话木马(最新免杀php后门一句话)
  17. 模拟POST、Get 请求的工具----APIpost(中文版POSTMAN)
  18. 4735: C语言循环水题2
  19. 儿时的动画,你看过那些?-我国的动画片
  20. 【蓝桥杯】 阶乘约数:定义n的阶乘= 1 × 2 × 3 × · · · × n。 请问100 的阶乘有多少个约数。

热门文章

  1. Unity3d实现双人网络坦克大战
  2. Xcon北京黑客大会明天开幕
  3. 数据挖掘实战(6)——机器学习实现文本分类(今日头条tnews数据集)
  4. c/c++ accumulation
  5. 输入两个正整数,求其最大公约数和最小公倍数。
  6. 机考怎么作弊_公司想用电脑组织机考,但是人手有限,不能人工监考,可不可以使用电脑控制防止考试作弊呢?...
  7. 微信公众平台开发(93) 关闭微信浏览器
  8. 城市生态类毕业论文文献有哪些?
  9. 利用Vivado进行MicroBlaze处理器应用教程
  10. 2016全域大数据应用论坛11位嘉宾核心观点