Spring + MyBaits 日志初始化两遍的问题
偶然发现一个问题,记录一下以备查询。
问题:系统启动时发现日志初始化了两次
14:28:04.798 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
14:28:04.970 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
相关环境文件
mybatis-config.xml片段:
<settings>
<setting name="logImpl" value="SLF4J" /> <!-- 日志实现包 -->
</settings>
applicitionContext.xml片段:
<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="driverManagerDataSource" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>
既然是LogFactory打印的日志,先从LogFactory开始看,
public final class LogFactory {
private static Constructor<? extends Log> logConstructor;
static { // 加载时按顺序尝试日志实现,这是第一条日志的输出
tryImplementation(new Runnable() {
public void run() {
useSlf4jLogging();
}
});
tryImplementation(new Runnable() {
public void run() {
useCommonsLogging();
}
});
// 忽略部分代码
tryImplementation(new Runnable() {
public void run() {
useNoLogging();
}
});
}
private LogFactory() {
// disable construction
}
public static Log getLog(Class<?> aClass) {
return getLog(aClass.getName());
}
public static Log getLog(String logger) {
try {
return logConstructor.newInstance(new Object[] { logger });
} catch (Throwable t) {
throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t);
}
}
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
public static synchronized void useSlf4jLogging() {
setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
}
public static synchronized void useCommonsLogging() {
setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);
}
public static synchronized void useStdOutLogging() {
setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);
}
public static synchronized void useNoLogging() {
setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);
}
private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) { // 当加载日志实现成功一次后,这里logConstructor已经不为null
try {
runnable.run();
} catch (Throwable t) {
// ignore
}
}
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
Constructor<? extends Log> candidate = implClass.getConstructor(new Class[] { String.class });
Log log = candidate.newInstance(new Object[] { LogFactory.class.getName() });
log.debug("Logging initialized using '" + implClass + "' adapter.");
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
}
}
可以看出在spring容器启动时,已经加载了一个“org.apache.ibatis.logging.slf4j.Slf4jImpl”;
那么第二条日志是什么时候输出呢?
容器在构造SqlSessionFactoryBean时,需要mybatis-config.xml,因为有<setting name="logImpl" value="SLF4J" />这一条配置,
所以在解析到这一条时调用了org.apache.ibatis.session.Configuration这个类又执行了一次初始化,
顺序SqlSessionFactoryBean -> SqlSessionFactoryBuilder -> XMLConfigBuilder -> Configuration
最终Configuration中:
public void setLogImpl(Class<?> logImpl) {
if (logImpl != null) {
this.logImpl = (Class<? extends Log>) logImpl;
LogFactory.useCustomLogging(this.logImpl);
}
}
由此也看明白了配置日志实现相当于手动执行org.apache.ibatis.logging.LogFactory.useSlf4jLogging(),mybatis文档中也写到了:
如果要手动调用LogFactory.use***Logging()方法,请在调用所有其他MyBatis方法前调用它。另外,只有在相应日志实现存在 的前提下,调用对应的方法才是有意义的,否则MyBatis一概忽略。如你环境中并不存在Log4J,你却调用了 相应的方法,MyBatis就会忽略这一调用,代之默认的查找顺序查找日志实现。
Spring + MyBaits 日志初始化两遍的问题的更多相关文章
- spring aop 加在Controller层造成类初始化两遍
写一个测试项目,在配置动态数据源的时候采用的AOP切面到Controller层中,根据参数判断是否切合数据源,结果发现,每次Controller层的类都会初始化两次! 后来测试发现,把切面放到Serv ...
- srping mvc 集成CXF 导致类初始化两遍
cxf依赖于spring的ContextLoaderListener,而spring mvc 则依赖于DispatcherServlet. 初始化DispatcherServlet的时候会依赖初始化一 ...
- tomcat启动项目被重新加载,导致资源初始化两遍
之前没有遇到过这个问题,配了三天的项目了,惊人啊!!!各种怪问题全被我赶上了.真有种骂人的冲动. tomcat启动项目时,项目资源被加载两遍. 原因:配置虚拟目录导致,项目被重新加载. <Hos ...
- log4j2 日志打两遍的问题
在使用log4j2的时候,一般都需要不同的日志分类打印不同的日志等级,如下面的配置 <!-- 用于指定log4j自动重新配置的监测间隔时间,单位是秒 --> <configurati ...
- Spring + MyBaits java.lang.reflect.InvocationTargetException 启动日志报错
调试发现 实例化 class org.apache.ibatis.logging.slf4j.Slf4jImpl时发生异常,所以 slf4j jar 问题解决: http://www.cnblogs. ...
- 从启动日志看Spring IOC的初始化和Bean生命周期
一.Tomcat中启动IoC容器的日志 启动Tomcat等容器时,控制台每次都打印出一些日志. 最近刚好在研究Spring源码,所以换个角度,从启动日志来简单的看看Spring的初始化过程! 以下是T ...
- spring项目的 context root 修改之后,导致 WebApplicationContext 初始化两次的解决方法
修改了 spring web 项目的 context root 为 / 之后,在启动项目时,会导致 WebApplicationContext 初始化两次,下面是其初始化日志: 第一次初始化: 四月 ...
- 【问题记录】eclipse启动web项目时,spring会初始化两次
背景:一个tomcat,一个eclipse,一个SSM框架的web项目.在eclipse中新建tomcat服务器,默认配置,然后在服务器配置中将Server Locations改成Use Tomcat ...
- 项目部署到tomcat Root中后导致 WebApplicationContext 初始化两次的解决方法
上一篇文章刚说项目部署到tomcat的ROOT中,今天就发现一个问题.通过eclipse启动tomcat时候,WebApplicationContext 初始化两次: 现象: 通过eclipse控 ...
随机推荐
- 细说分布式Redis架构设计和踩过的那些坑
细说分布式Redis架构设计和踩过的那些坑_redis 分布式_ redis 分布式锁_分布式缓存redis 细说分布式Redis架构设计和踩过的那些坑
- Using DTrace to Profile and Debug A C++ Program
http://www.oracle.com/technetwork/server-storage/solaris/dtrace-cc-138561.html
- DELPHI跨平台的临界替代者
在WINDOWS里面使用临界来保护多线程需要访问的共享对象,现在,DELPHI有了新的跨平台临界保护者--System.TMonitor 代码演示如下: FConnections := TObject ...
- burpsuite破解版
来源:http://www.vuln.cn/8847
- Bag-of-words模型、TF-IDF模型
Bag-of-words model (BoW model) 最早出现在NLP和IR(information retrieval)领域. 该模型忽略掉文本的语法和语序, 用一组无序的单词(words) ...
- 【转】C++函数的重载、覆盖和隐藏区别
网上看到的关于C++函数的重载.覆盖和隐藏区别的回答,如下(其内容来源于C++面试宝典中一道题目): a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:( ...
- Robotframework集成jenkins执行用例
Robotframework+jenkins配置 假设我们完成了一个模块的用例设计,可是想晚上9点或凌晨运行,这时候该怎么实现呢?jenkins可以很好解决我们的疑难. Jenkins安装 这里简单说 ...
- JMeter 系列之—-01使用
用Jmeter 做压测,总体与LoadRunner 类似: 一.线程组 1. 线程数 2. 循环次数 单个线程循环次数 3. Ramp-up Period(in seconds) [1]决定多长时间启 ...
- Android学习路线(十九)支持不同设备——支持不同(Android)平台版本号
当最新的Android版本号为你的应用提供着非常棒的APIs时.你却要在很多其它的设备更新之前继续支持老的系统版本号.这篇课程怎样在继续支持低版本号的系统的情况下使用新版本号的高级API. Platf ...
- 动态追踪技术 Dynamic Tracing
https://openresty.org/posts/dynamic-tracing/ 工欲性能调优,必先利其器(2)- 火焰图| PingCAP https://pingcap.com/blog- ...