Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突...
和平的日子不在了,让我们一起来看看究竟发生了什么...
首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。
为什么commons-logging和jcl-over-slf4j会有冲突呢?看一下它们的类结构
很清晰的可以看到jcl-over-slf4j 重写了 commons-logging...
还有slf4j-api的实现呢,同样看类:
其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。
顺着研究,继续看一下slf4j的源码及流程
1.测试类
- package com.taobao.wuzhong.log;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.junit.Test;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * DESC:
- *
- * Copyright: Copyright 2011 m.taobao.com
- *
- * @author wuzhong@taobao.com
- * @time 2011-4-6 下午03:42:11
- * @version 1.0
- **/
- public class LogTest {
- // Logback tries to find a file called logback.groovy in the classpath.
- // If no such file is found, logback tries to find a file called
- // logback-test.xml in the classpath.
- // If no such file is found, it checks for the file logback.xml in the
- // classpath..
- // If neither file is found, logback configures itself automatically using
- // the BasicConfigurator which will cause logging output to be directed to
- // the console.
- @Test
- public void test() {
- //commons-logging的方式获取
- Log log = LogFactory.getLog(LogTest.class);
- //slf4j直接的方式获取,推荐用这个
- Logger log2 = LoggerFactory.getLogger(LogTest.class);
- log.debug("eeeeee {} {} {}");
- log2.debug("{} {} {}", new String[] { "a", "b", "c" });
- }
- }
logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
- Log instance = null;
- // protect against concurrent access of loggerMap
- synchronized (this) {
- instance = (Log) loggerMap.get(name);
- if (instance == null) {
- Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理过去了
- if(logger instanceof LocationAwareLogger) {
- instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger); //包装了一层,做适配
- } else {
- instance = new SLF4JLog(logger);
- }
- loggerMap.put(name, instance);
- }
- }
- return (instance);
loggerFactory 会调用getILoggerFactory().getlOgger()
- LoggerFactory.java
- public static ILoggerFactory getILoggerFactory() {
- if (INITIALIZATION_STATE == UNINITIALIZED) {
- INITIALIZATION_STATE = ONGOING_INITILIZATION;
- performInitialization();
- }
- switch (INITIALIZATION_STATE) {
- case SUCCESSFUL_INITILIZATION:
- return getSingleton().getLoggerFactory();
- case FAILED_INITILIZATION:
- throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
- case ONGOING_INITILIZATION:
- // support re-entrant behavior.
- // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
- return TEMP_FACTORY;
- }
- throw new IllegalStateException("Unreachable code");
- }
- private final static void performInitialization() {
- bind();
- versionSanityCheck();
- singleImplementationSanityCheck();
- }
这里的bind很关键,这里动态的绑定了slf4j-api的实现机制
- static {
- SINGLETON.init();
- }
- /**
- * Package access for testing purposes.
- */
- void init() {
- try {
- try {
- new ContextInitializer(defaultLoggerContext).autoConfig();
- } catch (JoranException je) {
- Util.reportFailure("Failed to auto configure default logger context",
- je);
- }
- StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
- contextSelectorBinder.init(defaultLoggerContext, KEY);
- initialized = true;
- } catch (Throwable t) {
- // we should never get here
- Util.reportFailure("Failed to instantiate ["
- + LoggerContext.class.getName() + "]", t);
- }
- }
获取配置信息初始化
- autoConfig ….
- public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
- ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
- URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
- if (url != null) {
- return url;
- }
- url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url);
- }
- if (url != null) {
- return url;
- }
- url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url);
- }
- return url;
- }
- public void autoConfig() throws JoranException {
- StatusListenerConfigHelper.installIfAsked(loggerContext);
- URL url = findURLOfDefaultConfigurationFile(true);
- if (url != null) {
- configureByResource(url);
- } else {
- BasicConfigurator.configure(loggerContext);
- }
- }
最后画张流程图总结下,^_^
总结: log框架应该很好的诠释了 facade , adapter , 实现上还是比较简单的,很好的做到了接口和实现的分离,对今后的代码组织有一定的启发
相关推荐
JAVA通用快速开发框架源码 注意:不带技术支持,有帮助文件,虚拟商品...· 日志管理:SLF4J 1.7、Log4j · 单元测试:JUnit 4.12 · API接口文档:Swagger 2.7.0 · 页面交互:Vue 2.x + Bootstrap+ HTML5 + CSS3
日志管理:SLF4J 1.7、Log4j JS框架:Vue 2.5.1,iview,layer 3.0.3,jquery 2.2.4,jqgrid 5.1.1 CSS框架:Twitter bootstrap3.3.7。 富文本:froala_editor1.2.2 3 特点 免费完整开源:基于MIT协议,源代码完全...
JAVA通用快速开发框架源码 通用快速开发框架是一套轻量级的权限系统,主要包括用户管理、角色管理、部门管理、菜单管理、...· 日志管理:SLF4J 1.7、Log4j · 单元测试:JUnit 4.12 · API接口文档:Swagger 2.7
- 日志管理:SLF4J 1.7、Log4j - 页面交互:Vue2.x **软件需求** - JDK1.8 - MySQL5.5+ - Maven3.0+ **本地部署** - 通过git下载源码 - 创建数据库renren_security,数据库编码为UTF-8 - 执行db/...
核心框架:Spring Boot 2.0 安全框架:Apache Shiro 1.4 视图框架:Spring MVC 5.0 持久层框架:MyBatis 3.3 定时器:Quartz 2.3 数据库连接池:Druid 1.0 日志管理:SLF4J 1.7、Log4j 页面交互:Vue2.x
无所不能SpringMVC 小服务程序Spring安全Spring测试Spring核心,bean,上下文,上下文支持SpringAOP 速度jstl 日志记录(log4j,slf4j) 球衣+Spring数据库我们选择的数据库是PostgreSQL如何建造分别在...
本系统为就业管理系统,主要围绕高校毕业生的毕业情况进行跟踪和分析,为学校领导对专业设置优化,为高校毕业生就业方向提供参考。...日志:SLF4J 1.7、Log4j 前端框架:Layui,ztree,jquery,echarts
增加Slf4jLogger实现,然日志配置能基于任何Slf4j下的log实现,如logback public class Slf4jLogFactory implements ILoggerFactory 3.基础model实现,实现基础的常用的部分功能用于复用 public List ...
初学JAVA的同学可以下载源代码来进行学习交流; 技术框架 核心框架:Spring Framework 4 安全框架:Apache Shiro 1.2 视图框架:Spring MVC 4 持久层框架:MyBatis 3 数据库连接池:Alibaba Druid 1.0 日志管理:SLF...
Springboot快速开发项目描述通用快速开发框架是一套轻量级的权限系统,主要包括用户管理,角色管理,部门管理,菜单管理,SQL监视,定时任务,...SLF4J 1.7,Log4j单元测试:JUnit 4.12 API接口文档:Swagger 2.7.0页面
Dropwizard 模板Dropwizard 是一个微服务框架。 此模板显示了我们添加到 Dropwizard 的各种配置和库。... 使用 Log4J 或 SLF4J 进行集中日志记录有 Mockito 和 Hamcrest 来协助测试。 用于依赖注入的 Google Gu