LoggerFactory.getLogger 理解

参考:【java】slf4j中的适配器与桥接是怎样工作的?_哔哩哔哩_bilibili

<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.7.30</version>
</dependency>


//import对应的信息:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/*
LoggerFactory.getLogger用法
java开发过程中经常需要打印日志信息,往往会在每个类的第一行加上形如以下代码:

protected static final Logger logger = LoggerFactory.getLogger(XXX.class);

目的:使用指定的类XXX初始化日志对象,方便在日志输出的时候,可以打印出日志信息所属的类。

示例:

protected static final Logger logger = LoggerFactory.getLogger(XYZ.class);

logger.debug("hello world");

输出:XYZ:hello world
*/

2. @Slf4j用作日志输出

@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写下面这段代码,并且想用log

private final Logger log = LoggerFactory.getLogger(XYZ.class);

@Slf4来代替;这样就省去这段很长的代码【添加了该注释之后,就可以在代码中直接饮用log.info( ) 打印日志了】

import ...

@Slf4j
public class Controller {


    public String getInfo() {
        log.info("日志信息");
    }
}

3. log4j.properties配置文件

### 设置###
log4j.rootLogger = debug,stdout,D,E
 
### 输出信息到控制抬 ###
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
 
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
 
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

上面内容说明

%m   输出代码中指定的消息
%p   输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL 
%r   输出自应用启动到输出该log信息耗费的毫秒数 
%c   输出所属的类目,通常就是所在类的全名 
%t   输出产生该日志事件的线程名 
%n   输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n” 
%d   输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH\:mm\:ss},输出类似:2015-12-09 22:05:36  
%l   输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:TestLog4j:16 

  

1. 引入slf4j的一个疑问。。。

<dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.7.30</version>
</dependency>

疑问:为什么单纯的引入slf4j-log4j12就可以实现slf4j了?完全不需要依赖log4j吗?这个不是log4j实现支持slf4j才会引入的依赖库[slf4j-log4j12]吗?

 本质上可以看到:slf4j-log4j12已经依赖了log4j和slf4j-api了。所以不需要了哈

2. 附加问题?这里只引入(log4j和slf4j-api是否可行,为什么?)

如上:不可行,在做日志的实现(绑定),slf4j-api提供了接口,log4j是具体的实现,没有东西把这两个联系起来,也就是没有适配层。。。 所以会出错【下图可以看到】

同理:logback类似

还是因为slf4j-api是对应的接口,而实现就是logback-classic/logback-core 

3. 为什么说logback-classic实现了slf4j呢?

可以看到引入logback-classic的时候,也会自动依赖slf4j-api(所以说,这里也实现了slf4j,可以直接使用呢)

4. logback-classic是先于slf4j实现的,为什么会实现这个呢?

是因为之前的版本logback-classic还没有实现slf4j。本质上严格意义上需要引入slf4j-api的,版本1.2.3之后加入了(包括之前)实现,所以支持了slf4j呢

早先上怎么支持slf4j呢?(slf4j是一个接口)

 

来源并整理出的下文,感谢free_coder:【java】20分钟搞清log4j/logback/log4j2/slf4j || 如何统一日志标准_哔哩哔哩_bilibili

注:下文的配置都是输出到控制台,目的是为了方便校验查看

1. log4j+slf4j-log4j12 ——》slf4j 

<dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
<!--        为了使得log4j支持slf4j,所以刻意引入slf4j-log4j12
            目的是为了基础库升级到slf4j标准-->
<!--        <dependency>-->
<!--            <groupId>org.slf4j</groupId>-->
<!--            <artifactId>slf4j-log4j12</artifactId>-->
<!--            <version>1.7.30</version>-->
<!--        </dependency>-->
    </dependencies>
### 设置###
log4j.rootLogger = info,console

### 输出信息到控制抬 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n
#log4j.appender.console.layout.ConversionPattern = %c:%m%n

2.  log4j2  + log4j-slf4j-impl  ——》slf4j

<dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.6.1</version>
        </dependency>

                <!--        为了使得log4j2支持slf4j,所以刻意引入log4j-slf4j-impl目的是为了基础库升级到slf4j标准-->
<!--        <dependency>-->
<!--            <groupId>org.apache.logging.log4j</groupId>-->
<!--            <artifactId>log4j-slf4j-impl</artifactId>-->
<!--            <version>2.9.0</version>-->
<!--        </dependency>-->
    </dependencies>
### 设置###
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n

3. logback。   //logback默认已经实现了slf4j这个门面 【标准】

<dependencies>
    <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

</dependencies>

logback.xml配置文件 

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
       <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
          <encoder>
             <pattern>[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n</pattern>
          </encoder>
       </appender>

       <root level="debug">
          <appender-ref ref="console" />
       </root>
</configuration>

总结:

logback
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
LoggerFactory.getLogger
log4j
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
org.apache.log4j.Logger
Logger.getLogger
log4j2
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.6.1</version>
</dependency>
org.apache.logging.log4j.LogManager;
org.apache.logging.log4j.Logger;
LogManager.getLogger

0. 新工程pom使用本地工程生成的库

本地工程如下,可以通过mvn install的方式安装到本地项目中

新工程pom就可以使用了

当一个项目有多个依赖库,同时是不同日志系统实现,如果该项目里面没有指定配置文件,那么会使用原有库依赖的。。。会在各自的项目中进行查找(这种是无冲突的)

 当然,如果该项目中有指定,那就会使用当前配置下的配置文件

代表存在多个multiple slf4j。最后选择了log4j实现的日志系统 。所以最后展示的时候会统一使用new 4j【可以看到,最后统一使用new 4j进行了所有日志的打印】

 如何指定日志实现库?【如果系统只有一个实现了slf4j】

使用exclusion方式进行求解

也可使用不存在的依赖

PRO ——》A(log4j)

        ——》B(slf4j ——log4j2)

        ——》C(slf4j——logback)

正常如上是没有问题的。也不会冲突(exclusion适配后),那如何让A也满足slf4j的标准呢?也就是说如何让 没支持slf4j的满足slf4j呢?

需要如下:先排除掉log4j,同时强行使用log4j-over-slf4j

log4j2支持slf4j的使用方式

slf4j中的适配器与桥接是怎样工作的?

门面标准slf4j,全称是slf4j-api【门面的设计模式】

1. logback是通过接口实现slf4j-api

 桥接:over(依赖使用的日志实现是log4j,当前工程想升级到slf4j,那么可以直接使用桥接)

原理:log4j-over-slf4j把log4j里面的类全部进行了重写(重写的含义是:保持package和类名完全一致,然后把类里面的东西修改了)

注:类名一致的话,会加载第一个。。。

注:maven依赖的前后顺序也很重要呢

所以有两种做法:1(pom中引入不存在的log4j)2(显式的把log4j-over-slf4j写在前面)

情景1。。。最终使用到的是log4j-over-slf4j

情景2。。。最终使用的Logger是log4j

上面两张图的效果一致


版权声明:本文为weixin_35821291原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。