log4j mysql 非法字符_log4j与logback包冲突原因及解决,不可忽视的Warning

场景

一个简单的spring-boot程序,需要用kafka做消息队列,于是在maven中引入kafka依赖,一切看似没问题,在启动时,打印出Warning信息:

SLF4J: Class path contains multiple SLF4J bindings.

SLF4J: Found binding in [jar:file:/xxx/learning-slf4j-multiple-bindings/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: Found binding in [jar:file:/xxx/learning-slf4j-multiple-bindings/WEB-INF/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]

SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

原因分析

通过警告消息,可以简单的看出是slf4j绑定发生问题,有多个StaticLoggerBinder.class存在,即slf4j-log4j12和logback-classic冲突。

疑惑点1是我并没有手动引入slf4j-log4j12依赖,依赖jar包是被自动引入的,通过maven自带工具分析依赖路径,可以看出是kafka依赖于slf4j-log4j12,自动导入的依赖包。

3696adfb32d684c73c2b6fe93fb3ec84.png

e39f999f8bf981c5701592dafbd65d03.png

日志绑定的机制分析

从日志对象开始探究slf4j的绑定方式。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

···

private final Logger logs = LoggerFactory.getLogger(***.class);

LoggerFactory.getLogger()方法:(下述均只保留关键逻辑代码 )

public static Logger getLogger(Class> clazz) {

Logger logger = getLogger(clazz.getName());

···

return logger;

}

public static Logger getLogger(String name) {

ILoggerFactory iLoggerFactory = getILoggerFactory();//看这里

return iLoggerFactory.getLogger(name);//根据名字返回一个Logger实例对象

}

ILoggerFactory是一个接口,归属package org.slf4j;仅存在一个方法为:

public Logger getLogger(String name);

接下来就是看看getILoggerFactory()的真面目:

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");

}

可以看到performInitialization()是进行初始化的方法:

private final static void performInitialization() {

bind();

···

}

performInitialization()内部调用bind()方法:

private final static void bind() {

try {

Set staticLoggerBinderPathSet = null;

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) {...

} catch (java.lang.NoSuchMethodError nsme) {...

} catch (Exception e) {...}

}

其中关键在于findPossibleStaticLoggerBinderPathSet()方法,终于到了查找绑定相关的部分内容,可以看到是查找所有的"org/slf4j/impl/StaticLoggerBinder.class"类并加载,同时while循环里,将可能存在的多个StaticLoggerBinder.class路径均加入Set返回。

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

static Set findPossibleStaticLoggerBinderPathSet() {

Set staticLoggerBinderPathSet = new LinkedHashSet();

try {

ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();

Enumeration paths;

if (loggerFactoryClassLoader == null) {//看这里

paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);

} else {

paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);

}

while (paths.hasMoreElements()) {//看这里

URL path = paths.nextElement();

staticLoggerBinderPathSet.add(path);

}

} catch (IOException ioe) {

Util.report("Error getting resources from path", ioe);

}

return staticLoggerBinderPathSet;

}

返回到bind()方法中:

private final static void bind() {

···

staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();

reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);//看这里

···

}

···

private static void reportMultipleBindingAmbiguity(Set binderPathSet) {

if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) {

Util.report("Class path contains multiple SLF4J bindings.");

for (URL path : binderPathSet) {

Util.report("Found binding in [" + path + "]");

}

Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");

}

}

这里可以看到reportMultipleBindingAmbiguity()里判断是否发生多重绑定,就是打印文章开头Warning信息的地方。

成功加载StaticLoggerBinder后,在bind()方法中调用其getSingleton()方法得到单例,并修改INITIALIZATION_STATE状态,至此完成日志框架的绑定。

private final static void bind() {

if (!isAndroid()) {

staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();

reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);

}

StaticLoggerBinder.getSingleton();//看这里

INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;

reportActualBinding(staticLoggerBinderPathSet);

···

}

最后附上slf4j-api-1.7.25.jar和logback-classic-1.2.3.jar的目录结构供参考:

a36d2b941772610f97ce7d5fd6c026b0.png

82084cd20acfb05c61a59350622a3b66.png

解决方案

分析了原因,那么解决方案自然很简单,就是剔除不需要的依赖包,此处就是在kafka的依赖中剔除slf4j-log4j12。maven项目中可以通过exclusions标签来完成。

org.apache.kafka

kafka_2.11

0.10.0.1

org.slf4j

slf4j-log4j12

本文就简单分析了日志加载绑定的过程,如有遗漏请不吝指出。

Maven类包冲突终极三大解决技巧 mvn dependency:tree

Maven对于新手来说是,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫. Maven对于老手来说是,因为它无所不能 ...

Maven中 jar包冲突原理与解决办法

Maven中jar包冲突是开发过程中比较常见而又令人头疼的问题,我们需要知道 jar包冲突的原理,才能更好的去解决jar包冲突的问题.本文将从jar包冲突的原理和解决两个方面阐述Maven中jar包冲 ...

[转]Maven类包冲突终极三大解决技巧

举例 A依赖于B及C,而B又依赖于X.Y,而C依赖于X.M,则A除引B及C的依赖包下,还会引入X,Y,M的依赖包(一般情况下了,Maven可通过等若干种方式控制传递依赖).这 ...

jar包冲突常用的解决方法

jar包冲突常见的异常为找不到类(java.lang.ClassNotFoundException).找不到具体方法(java.lang.NoSuchMethodError).字段错误( java.l ...

was(websphere application server)中用apache的httpclient时jar包冲突问题的解决

这个问题可以用was的共享库解决. 具体解决方案如下图所示: 对于有多个jar包冲突时,为每个冲突的jar包都新建一个共享库即可. 我之前的错误操作是以为一个共享库可以添加多个冲突的jar包用分号和逗 ...

部分APP无法代理抓包的原因及解决方法

引言 HTTP应用层的抓包已经成为日常工作测试与调试中的重要一环,最近接触新项目突然之间发现之前的抓包手段都不好使了,顿时模块与模块之间的前端与服务之间的交互都变成了不可见,整个人都好像被蒙住了眼睛. ...

[log4j]Slf4j的包冲突

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFa ...

Android手机出现"已安装了存在签名冲突的同名数据包"的原因及解决办法

http://blog.csdn.net/dyllove98/article/details/8830264 如果你不是开发者:如果你在android上更新一个已经安装过较早版本软件时,安装到最后一步 ...

NPM 无法下载任何包的原因,解决方法

前几天发现NPM 无法现在任何的包 通过npm i testPackage -ddd 发现 是卡在了 npm verb addRemoteTarball 这行,google后发现 是有多个tmp地址, ...

随机推荐

C语言 预处理一(文件包含--#include)

//预处理命令不需要在结束末尾加":" //#inlude可以包含任意类型的文件 //#inlude 将一个源文件的全部内容包含到另一个源文件中,成为它的一个部分,文件包含的一般格 ...

DX11.2 Tiled Resource Pool

Nvidia white paper : https://developer.nvidia.com/content/taking-advantage-directx112-tiled-resource ...

Android学习之Animation(一)

3.0以前,android支持两种动画模式,Tween Animation,Frame Animation,在android3.0中又引入了一个新的动画系统:Property Animation,这三 ...

JVM内存简单总结

根据自己的认识,简单总结下Java中的数据存储及内存分析. Java中的内存大致可以分为三块:栈内存.堆内存.方法区内存,看图说话. 1).栈 栈(stack):栈是限定仅在表头进行插入和删除操作的线 ...

CCF CSP 201503-2 数字排序 (map+自定义排序)

题目链接:http://118.190.20.162/view.page?gpid=T26 返回试题列表 问题描述 试题编号: 201503-2 试题名称: 数字排序 时间限制: 1.0s 内存限制: ...

Rabbit原理理解

1.RabbitMQ知多少   圣杰 2.[RabbitMQ]——三种Exchange模式(Fanout.Direct.Topic) https://blog.csdn.net/hao134838/a ...

本学期C#学习个人总结

本学期C#的学习结束了,我在这里作一下总结.我还记得陈老师在第一节课上说过,学任何东西,都要学结构,否则你不会学好.当我听到这句话的时候,没有放在心上,可是随着C#学习的不断深入,我越来越发现许多知识 ...

java.lang.Enum

参考博客链接 java枚举类型的优势在哪里? Java 枚举(enum) 详解7种常见的用法

mysql 递归查找菜单节点的所有子节点

背景                                                                                                   ...

第二次作业:Git的安装与使用

---恢复内容开始--- 本次作业要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 1.首先安装git bash软件, ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值