【转】SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J

2024-02-06 23:32

本文主要是介绍【转】SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!



http://foxarmywave.blog.163.com/blog/static/173860086201161954015164/


我们前面已经讲过了 SLF4J 的两种用法:SLF4J+Log4J  和 SLF4J+Logback,那是在比较理想的情况下,所用组件只使用了 SLF4J 这一种统一日志框架的时候。可是 JCL 一直影响深远,SLF4J 渐入佳境的时个,在你的项目中很可能所用的组件,它们分别用了 JCL 和 SLF4J 两种组件。比如说在项目中用了 Hibernate 3.5 和 Struts,或其他 Apache 的一些开源组件,你大约也不想用了 SLF4J 的组件日志信息输出到 A 处,用了 JCL 的组件日志输出到 B 处,那你自己写的代码中的日志信息该往哪儿写呢?


中国人一直都愿追求大一统,不喜欢城邦制的便于分而治之。但说到日志输出还是得统一到单一通道中来,一方面多个通道浪费资源,另方面也便于配置和管 理。那么既然 SLF4J 是趋势,当 SLF4J 和 JCL 被丢到一个坛子里,首先会让 SLF4J 为主,JCL 为辅,也就是要把 JCL 桥接到 SLF4J 上来,通过 SLF4J 统一输出日志信息。于是也就是这篇要介绍的 SLF4J 使用模式:JCL-Over-SLF4J+SLF4J。


从前面对 SLF4J 的认识可知,即使把 JCL 转嫁到 SLF4J,还是无法输出日志,还需要一种日志实现,下层该用 Log4J 还得用 Log4J,想用 Logback 还是要用 Logback。所以到了 SLF4J 后还得往下走,也就是前面那两条路 SLF4J+Log4J 和 SLF4J+Logback,本篇使用 SLF4J 的模式具体就要分为:


JCL-Over-SLF4J+SLF4J+Log4J 和 JCL-Over-SLF4J+SLF4J+Logback, 这两种实现方式差不多。只是分别用的 jar 包和配置文件不同,SLF4J+Log4J 和 SLF4J+Logback 原来要哪些文件现在还是需要那些文件,只是都要加上 jcl-over-slf4j-1.5.11.jar 包。这里说明 JCL-Over-SLF4J+SLF4J+Logback 的方式。


需要的配置文件和组件包,下面四个 jar 文件和一个 xml文件都是要放在项目的 ClassPath 上。


1. slf4j-api-1.5.11.jar
2. logback-core-0.9.20.jar
3. logback-classic-0.9.20.jar
4. logback.xml 或 logback-test.xml
5. jcl-over-slf4j-1.5.11.jar


第 1 和第 5 个包在 http://www.slf4j.org/download.html 处下载,第二第三个包在 http://logback.qos.ch/download.html 下载,可能包文件名中的版本号有些差异。


下面是一个最简单的 logback.xml 文件内容


01
02
03
04
05
06
07
08
09
10
11
12
<? xml version = "1.0" encoding = "UTF-8" ?>
< configuration >
   < appender name = "stdout" class = "ch.qos.logback.core.ConsoleAppender" >
       < encoder charset = "GBK" >
           < pattern >[Consociate] %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</ pattern >
       </ encoder >
   </ appender
   < root level = "DEBUG" >
     < appender-ref ref = "stdout" />
   </ root >
</ configuration >


为了看看效果,我们在输入的 pattern 中加入了 [Consociate],来检验是否统一到单一的日志通道中去了。


使用 了 JCL 和 SLF4J  的代码


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
package com.unmi;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestJCLOverSlf4j {
     //SLF4J 的 Logger
     private static final Logger logger = LoggerFactory.getLogger( "From SLF4J" );
     //JCL 的 Log
     private static final Log log = LogFactory.getLog( "From JCL" );
     //分别用上面的 logger 和 log 输出日志,从输出可以看到它们统一到一个通道中了
     public static void main(String[] args) {
         logger.info( "Hello {}" , "From SLF4J" );
         log.info( "Hello From JCL" );
     }
}


我们在上面代码中,既使用了 JCL 统一日志框架,也使用了 SLF4J 的统一日志框架。要注意一点,从 JCL 桥接过来的 log 不能输出参数化消息了。上面代码使用了 org.apache.commons.logging.Log,import org.apache.commons.logging.LogFactory,但你却用不着引入 commons-logging.jar 包。


执行上面的代码,看到输出:


[Consociate] 23:19:39.890 [main] INFO  From SLF4J - Hello From SLF4J
[Consociate] 23:19:39.921 [main] INFO  From JCL - Hello From JCL


很明显示 JCL 框架和 SLF4J 框架的日志输出都统一到了一个通道中来了,为什么呢? SLF4J 使用的是 Logback 输出的信息,这一点没问题的,而 JCL 是不认识 Logback 的,所以 JCL 框架的输出必然是绕道到 SLF4J,最后也是由 Logback 输出的。


实现分析:


我们打开 jcl-over-slf4j-1.5.11.jar,看到里面有两个包 org.apache.commons.logging 和 org.apache.commons.logging.impl,并有相应的类,这就是为什么,虽然在代码中有:


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


却不用把 commons-logging.jar 包引入到类路径上的原因。


再深入下 jcl-over-slf4j-1.5.11.jar,看到其中还有个文件 /META-INF/services/org.apache.commons.logging.LogFactory,内容为:


org.apache.commons.logging.impl.SLF4JLogFactory


# Axis gets at JCL through its own mechanism as defined by Commons Discovery, which
# in turn follows the instructions found at:
# http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service Provider


JCL 运行时使用了 SLF4JLogFactory,从而完成了 JCL 的日志实现委托给了 SLF4J,再由 SLF4J 进一步完成具体的日志输出。


采用 JCL-Over-SLF4J+SLF4J+Log4J 使用模式也是相似的,这里就不详述了。总结下就是 JCL 把 SLF4J 当作它的日志实现。


再来想象个问题:如果我们把这两个包 jcl-over-slf4j-1.5.11.jar 和 slf4j-jcl-1.5.11.jar 都放到 ClassPath 下会有什么情况呢?JCL 代理给 SLF4J,SLF4J 又绑定到 JCL,对了,死循环,StackOverFlow 错误:


SLF4J: Detected both jcl-over-slf4j.jar AND slf4j-jcl.jar on the class path, preempting StackOverflowError.
SLF4J: See also
http://www.slf4j.org/codes.html#jclDelegationLoop for more details.
java.lang.ExceptionInInitializerError
at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:82)
at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:51)
at org.slf4j.LoggerFactory.getSingleton(LoggerFactory.java:230)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:121)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:112)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:275)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:248)
at com.unmi.TestJCLOverSlf4j.<clinit>(TestJCLOverSlf4j.java:10)
Caused by: java.lang.IllegalStateException: Detected both jcl-over-slf4j.jar AND slf4j-jcl.jar on the class path, preempting StackOverflowError. See also
http://www.slf4j.org/codes.html#jclDelegationLoop for more details.
at org.slf4j.impl.JCLLoggerFactory.<clinit>(JCLLoggerFactory.java:64)
... 8 more
Exception in thread "main"

这篇关于【转】SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685879

相关文章

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

SpringShell命令行之交互式Shell应用开发方式

《SpringShell命令行之交互式Shell应用开发方式》本文将深入探讨SpringShell的核心特性、实现方式及应用场景,帮助开发者掌握这一强大工具,具有很好的参考价值,希望对大家有所帮助,如... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

MySQL 分区与分库分表策略应用小结

《MySQL分区与分库分表策略应用小结》在大数据量、复杂查询和高并发的应用场景下,单一数据库往往难以满足性能和扩展性的要求,本文将详细介绍这两种策略的基本概念、实现方法及优缺点,并通过实际案例展示如... 目录mysql 分区与分库分表策略1. 数据库水平拆分的背景2. MySQL 分区策略2.1 分区概念

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

C语言函数递归实际应用举例详解

《C语言函数递归实际应用举例详解》程序调用自身的编程技巧称为递归,递归做为一种算法在程序设计语言中广泛应用,:本文主要介绍C语言函数递归实际应用举例的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录前言一、递归的概念与思想二、递归的限制条件 三、递归的实际应用举例(一)求 n 的阶乘(二)顺序打印

CSS去除a标签的下划线的几种方法

《CSS去除a标签的下划线的几种方法》本文给大家分享在CSS中,去除a标签(超链接)的下划线的几种方法,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧... 在 css 中,去除a标签(超链接)的下划线主要有以下几种方法:使用text-decoration属性通用选择器设置:使用a标签选择器,将tex

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

SpringBoot日志配置SLF4J和Logback的方法实现

《SpringBoot日志配置SLF4J和Logback的方法实现》日志记录是不可或缺的一部分,本文主要介绍了SpringBoot日志配置SLF4J和Logback的方法实现,文中通过示例代码介绍的非... 目录一、前言二、案例一:初识日志三、案例二:使用Lombok输出日志四、案例三:配置Logback一