基于Spring MVC的Web应用开发(2) - Log

上一篇文章我们使用SpringMVC搭建了一个简单WEB项目 - HelloWorld,注意到我们在pom.xml中仅仅加了一个依赖(dependency):

spring-webmvc-3.1.0.RELEASE.jar 
spring-asm-3.1.0.RELEASE.jar 
spring-beans-3.1.0.RELEASE.jar 
spring-context-3.1.0.RELEASE.jar 
spring-aop-3.1.0.RELEASE.jar 
spring-context-support-3.1.0.RELEASE.jar 
spring-core-3.1.0.RELEASE.jar 
commons-logging-1.1.1.jar 
spring-expression-3.1.0.RELEASE.jar 
spring-web-3.1.0.RELEASE.jar 
aopalliance-1.0.RELEASE.jar
spring-webmvc-3.1.0.RELEASE.jar
spring-asm-3.1.0.RELEASE.jar
spring-beans-3.1.0.RELEASE.jar
spring-context-3.1.0.RELEASE.jar
spring-aop-3.1.0.RELEASE.jar
spring-context-support-3.1.0.RELEASE.jar
spring-core-3.1.0.RELEASE.jar
commons-logging-1.1.1.jar
spring-expression-3.1.0.RELEASE.jar
spring-web-3.1.0.RELEASE.jar
aopalliance-1.0.RELEASE.jar

在上篇文章最后我们分析了各个spring模块的依赖关系,注意到commons-logging-1.1.1.jar被依赖进来了,它是由spring-core模块依赖的,spring-core是spring的核心模块,任何其他模块都要加载它,所以common-logging理所当然的加载进来了。

下面开始正题,日志,通常我们谈到Java中的日志,首先想到的就是Log4j,对不对,这货知名度之广,生命力之强,在Java开源软件中也是非常罕见的。但其实在Log4j诞生之前,已经有一个日志框架出现在Java开源社区,它就是commons-logging,Rod Jonson先生在设计Spring框架时还没有log4j,所以他只有选择commons-logging,我们看一下它的类结构,非常简单:

org.apache.commons.logging 
|- Log.class
|- LogConfigurationException.class
|- LogFactory.class
|- LogSource.class
org.apache.commons.logging.impl 
|- 一些具体的实现类
org.apache.commons.logging
|- Log.class
|- LogConfigurationException.class
|- LogFactory.class
|- LogSource.class
org.apache.commons.logging.impl
|- 一些具体的实现类

所以我们在Spring源代码中可以看到大量的类似于如下的代码片段:

org.springframework.core.env.AbstractEnvironment.java

package org.springframework.core.env; 
... 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
... 
publicabstractclass AbstractEnvironment implements ConfigurableEnvironment { 
... 
 protectedfinal Log logger = LogFactory.getLog(getClass()); 
... 
 publicvoid addActiveProfile(String profile) { 
 logger.debug(String.format("Activating profile '%s'", profile)); 
 ... 
 } 
}
package org.springframework.core.env;
...
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
...
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
...
    protected final Log logger = LogFactory.getLog(getClass());
...
    public void addActiveProfile(String profile) {
        logger.debug(String.format("Activating profile '%s'", profile));
	...	
    }
}

整个Spring框架都是这样使用commons-logging的。

问题来了,既然Spring框架已经原生支持commons-logging了,为什么我们在实际开发中很少使用它呢?以及如果我想使用其他日志框架,Spring如何配置呢?

下面我先翻译spring官方手册中有关日志的一段内容,看看Spring团队是如何解释的:

1.3.2 日志

日志是Spring中非常重要的依赖,因为 a)它是唯一的强制性的外部依赖,b)大家都喜欢从他们使用的工具中看到一些输出,c)Spring集成了非常多的第三方工具,这些工具也会选择一种日志依赖。应用开发者的目标之一经常是想把日志统一配置在整个应用的一个中央地方,包括所有外部组件。因为有如此众多的日志框架可供选择,所以这个目标比它看起来要困难得多。

Spring中强制性的日志依赖为Jakarta Commons Logging API(缩写JCL)。我们在Spring框架中编译了JCL,同时我们也使JCL的Log对象对于继承Spring框架的所有类都是可见的。对使用者来说很重要的一点是,Spring的所有版本都使用相同的日志库:这样就让迁移就变得很简单了,因为向后兼容性甚至在继承于Spring的应用中都得到了保护(自己意会啊,我是字面翻译 译者)。我们这么做的目的是使Spring中的任何模块都明确地依赖于commons-logging(JCL的官方实现),然后使所有其他的模块在编译时(at compile time)依赖于它。举个例子,如果你正在使用Maven,想知道你从哪里捡起(pick up)的common-logging依赖,我们说它来自于Spring,更明确的就是来自于核心模块spring-core。

commons-logging很好的一点就是你不再需要任何其他的东西来使你的应用工作起来。它有一个运行时发现(runtime discovery)算法来寻找其他日志框架,通过广为人知的classpath路径,和使用任何一个它合适的路径(或者你可以告诉它你需要的哪个路径)。如果以上说的都没有的话,你会很高兴的看到它实际使用了来自JDK(java.util.logging或者缩写为JUL)的日志。(即如果我们只加载了commons-logging,它实际上是通过JDK的类库里面的具体日志类来做日志输出的,JDK的日志类在java.util.logging包下,JDK类库真是事无巨细啊,不是吗? 译者)你应该发现你的Spring应用在大多数情况下都正常工作着,并很愉快地记录日志到控制台上。这是很重要的。

1.3.2.1 不要使用Commons Logging!

不幸的是,commons-logging虽然对于终端用户来说非常方便的,但这货的运行时发现算法是有问题的!如果我们能把时间倒流到Spring框架刚刚创建那会,我们会使用一个不同的日志依赖。第一选择也许会是Java的Simple Logging Facade(缩写SLF4J),这东东同样被很多其他工具使用着,这些其他工具和Spring一起工作在他们的应用里。

将commons-logging关掉非常简单:只要确保它不出现在运行时的classpath路径下即可。在Maven的术语中,你可以排除(exclude)依赖(dependency),因为Spring组件之间的依赖关系图已经明确了,所以你只需要做一次排除依赖即可:

slf4j-api-1.6.1.jar 
jcl-over-slf4j-1.6.1.jar 
slf4j-log4j12-1.6.1.jar 
log4j-1.2.16.jar
slf4j-api-1.6.1.jar
jcl-over-slf4j-1.6.1.jar
slf4j-log4j12-1.6.1.jar
log4j-1.2.16.jar

上面的译文中并没有详细解释这几个jar包,我来补充一下:

我们注意到commons-logging-1.1.1.jar没有了,但是注意看jcl-over-slf4j-1.6.1.jar这个jar包,你会发现里面的结构和类名同commons-logging-1.1.1.jar一模一样!

slf4j-api-1.6.1.jar为slf4j的api,slf4j-log4j12-1.6.1.jar就是slf4j同log4j连接的桥接器,及上文说的bridge,注意slf4j是一个日志门店(logging facade),它可以同各种各样的其他第三方日志框架对接。它并不提供具体日志实现。log4j-1.2.16.jar就不用多说了,它就是日志的具体实现,它会到classpath下发现log4j.xml的配置并初始化log4j配置参数。

相关推荐