原文地址
http://stephansun.iteye.com/blog/1457425
上一篇文章我们使用SpringMVC搭建了一个简单WEB项目 - HelloWorld,注意到我们在pom.xml中仅仅加了一个依赖(dependency):
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>3.1.0.RELEASE</version>
- </dependency>
- </dependencies>
所有被依赖加载进来的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
- |- 一些具体的实现类
所以我们在Spring源代码中可以看到大量的类似于如下的代码片段:
org.springframework.core.env.AbstractEnvironment.java
- 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组件之间的依赖关系图已经明确了,所以你只需要做一次排除依赖即可:
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>3.0.0.RELEASE</version>
- <scope>runtime</scope>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
现在我们的应用很可能已经坏掉了,因为classpath路径下已经没有JCL API的实现了,所以为了修复它我们不得不提供一个新的替代品。在下一个小节中我们将向你展示一个例子,该例子提供了一个使用SLF4J的JCL替代实现。
1.3.2.2 使用SLF4J
SLF4J相比commons-logging是一个在运行时(at runtime)更干净(clearner)的依赖并且更有效的,因为它使用编译时(compile-time)绑定替代了运行时发现(runtime discoveery),同时它也能集成这些基于运行时发现的其他日志框架。这也意味着你必须明确的知道你在运行时想要什么,并且声明它或者相应的配置它。SFL4J提供了和很多通用日志框架的绑定,所以你通常还是可以选择那个你已经在使用的日志框架,通过配置和管理将它绑定起来。
SLF4J提供了同许多通用日志框架的绑定,包括JCL,它也做反转(reverse):在其他日志框架和它自身之间做桥接。所以通过Spring使用SLF4J,你需要将commons-logging依赖替换为SLF4J-JCL桥(bridge)。一旦你完成了这点,来自Spring框架内部的日志响应会自动的转成来自SFL4J API的日志响应,因此如果你应用中的其他库也使用SLF4J的API,那么你会有一个单独的地方配置和管理日志。
一个通用的选择也许就是将Spring和SLF4J桥接起来,然后提供一个明确的SLF4J到Log4J的绑定。你需要提供4个依赖(同时排除已经存在的commons-logging):桥接(bridge),SLF4J API,到Log4J的绑定,最后是Log4J自身的实现。在Maven中,你这样做看起来象:
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>3.0.0.RELEASE</version>
- <scope>runtime</scope>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.5.8</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.5.8</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.5.8</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
哇,看起来仅仅为了得到一些日志,我们搞了好多依赖啊。恩,的确是,但这个是可选的(optional),而且它在遵守classload的问题上(with respect to classloader issues 实在是翻不出啊 译者)的日志表现形式比乏味的commons-logging要好多了,注意如果你在一个非常严格的容器中,比如OSGi平台,据说SLF4J也有性能上的优势,因为SLF4J是绑定在编译时(compile-time)而不是运行时的(runtime)。
SFJ4J使用者中有一个更通用的选择,这个选择使用更少的步骤,生成更少的依赖,它直接绑定到Logback,这会少了一些额外的绑定步骤,因为Logback直接实现了SLF4J,所以你只需要依赖两个库而不是4个(jcl-over-slf4j和logback)。如果你这样做了,你就也需要排除来自其他外部依赖(并非Spring)对slf4j-api的依赖,因为你在classpath下只能拥有一个版本的API。
1.3.2.3 使用Log4J
很多开发者使用Log4j这个日志框架来配置和管理日志。Log4j很有效并且口碑很好,事实上在我们团队内部构建和测试Spring时运行时使用的就是Log4J。Spring框架内部提供了一些工具来配置和初始化Log4J,所以在一些Spring模块的Maven的POM文件中你会看到一个可选的(optional)的编译时(compile-time)依赖的Log4j。
为了使Logj同默认的JCL依赖(commons-logging)一起工作,所有你需要做的就使将Log4j放到classpath路径下,然后提供一个配置文件(classpath的根路径下,log4j.properties或者log4j.xml)(什么是classpath的根路径? 译者)(log4j.properties和log4j.xml相比区别?优缺点? 译者)。所以对于Maven使用者下面这个就是你的依赖声明:
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>3.0.0.RELEASE</version>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.14</version>
- <scope>runtime</scope>
- </dependency>
- </dependencies>
这里有一个log4j.properties的简单sample,它将日志打到控制台上:
- log4j.rootCategory=INFO, stdout
- log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
- log4j.category.org.springframework.beans.factory=DEBUG
采用原生JCL的运行时容器(Runtime Containers with Native JCL)
很多开发者在一个容器中运行他们的Spring应用,而这些容器本身就提供JCL的实现类。IBM Websphere Application Server(缩写WAS)就是一个原型(archetype)。这经常会导致问题出现,不幸的是并没有一个银弹(silver bullet 软件行业术语,通过《人月神话》一书广为人知,不过我没看过,这货太古老了,没意思 译者)解决方案;简单的从你的应用中排除commons-logging在大多数情形下是不够的。
让我们把这个说的更清楚一点:问题报告通常并不是跟JCL相关,甚至不是commons-logging;而是他们将commons-logging绑定到另外一个框架(经常是Log4J)的做法。这就会失败,因为commongs-logging在旧的版本之间改变了运行时发现(runtime discovery)的方式,比如一些容器中还存在的(1.0)版本,和更现代的版本如大多数人现在使用的(1.1)版本。Spring不使用JCL API中任何不通用的部分,所以Spring框架内部不会出问题,但是一旦Spring或者你的应用试图做任何日志,你会发现绑定到Log4J不起作用了。
在这种WAS的条件下,我们可以做的最简单的事情就是反转(invert)类加载层级(class loader hierarchy)(IBM管它叫“parent last”),因此应用控制JCL依赖,而不是容器。这个选择并不总是开放的,但是有在开源社区(public domain)(是这样翻译的么? 译者)中大量的其他建议的替代方案,你的本钱(mileage)可能极度依赖于容器中精确的版本和特性。
ok,翻译完了,我们看以下具体的例子,基于上一篇的samples-web
pom.xml更新为:
- <dependencies>
- <!-- spring mvc -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-webmvc</artifactId>
- <version>3.1.0.RELEASE</version>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- logging -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.6.1</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.6.1</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.6.1</version>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.16</version>
- </dependency>
- </dependencies>
在src/main/resources中加入log4j.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
- <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
- <!-- Appenders -->
- <appender name="console" class="org.apache.log4j.ConsoleAppender">
- <param name="Target" value="System.out" />
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%-5p: %c - %m%n" />
- </layout>
- </appender>
- <!-- Root Logger -->
- <root>
- <priority value="info" />
- <appender-ref ref="console" />
- </root>
- </log4j:configuration>
搞定,这就是所有要做的工作,增加了
- 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配置参数。
相关推荐
SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架集成。在构建SSH框架时,每个框架都扮演着不同的角色,以提供一个高效、可扩展的后端架构。现在我们来详细了解一下搭建SSH...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,专门用于构建可扩展和模块化的 Web 应用程序。在提供的压缩包文件中,包含了 Spring MVC 开发所需的一些核心库,这些库是 Spring MVC...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。在本压缩包 "springMVC3.0.5常用的所有jar包.zip" 中,包含了一...
# 基于Spring MVC的简易Web应用 ## 项目概述 本项目是一个基于Spring MVC框架的简易Web应用,旨在展示如何从零开始搭建一个Spring MVC项目,并逐步添加新功能。项目涵盖了基本的Maven配置、Spring配置、web.xml...
这里提到的四个关键配置文件——`spring-mvc.xml`、`spring-mybatis.xml`、`web.xml`以及`log4j.properties`,对于一个基于Java的Web应用来说至关重要,特别是使用Spring MVC和MyBatis框架的时候。接下来,我们将...
- `org.springframework.web.struts-3.0.5.RELEASE.jar`:此包提供了与Apache Struts框架的集成,使得基于Struts的应用程序可以利用Spring MVC的功能。 - `org.springframework.web.servlet-3.0.5.RELEASE.jar`:...
Spring MVC是Spring框架的一部分,专门用于构建Web应用程序,而Log4j是Java世界中广泛使用的日志记录工具。这个项目的目的是展示如何在Spring MVC应用中配置和使用Log4j来记录应用程序的日志信息。 在Spring MVC中...
总而言之,`spring-webmvc.jar`是构建基于Spring的Web应用的关键,而`jboss-logging.jar`和`jboss-logging-annotations.jar`则为日志管理提供了便利。理解这些jar包的功能和用法,能够帮助开发者更高效地开发和维护...
Spring MVC是Spring框架的一部分,它为开发基于Java的Web应用程序提供了一个强大的MVC实现。Spring MVC通过解耦业务逻辑、用户界面和应用程序控制,使得开发者能够专注于各自领域的代码编写。 **模型(Model)** ...
在IT行业中,Spring MVC是一个广泛使用的轻量级的MVC框架,用于构建高效、模块化且可测试的Java Web应用程序。而Logback是SLF4J(Simple Logging Facade for Java)的一个实现,是一个日志记录框架,它比Apache Log4...
Spring MVC 是一个强大的Java Web开发框架,用于构建可维护、可扩展且高度模块化的Web应用程序。这个名为"spring MVC step-by-step"的压缩包文件很可能包含了一步步教你如何使用Spring MVC进行开发的教程或者源代码...
通过本案例,我们可以学习如何使用 Spring、Spring MVC 和 MyBatis 框架来开发一个基于 Java 的 Web 应用程序,并掌握相关的技术和配置。 知识点: 1. Spring 框架的概述和应用场景 2. Spring MVC 框架的概述和...
综上所述,Spring的Web MVC构架模式以其高度的灵活性、可扩展性和组件化的特性,成为现代Web开发中广泛采用的框架,既可作为独立的Web解决方案,也可与其他技术无缝集成,以满足各种复杂应用的需求。
Spring MVC 是一个强大的Java web开发框架,用于构建可维护、可扩展且高度模块化的Web应用程序。Log4j,则是Java领域广泛使用的日志记录框架,它提供了灵活的日志配置、多级别的日志输出以及多种输出格式,使得...
Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它提供了模型-视图-控制器(MVC)架构模式来构建可维护、可扩展的Web应用。Log4j 是一个广泛使用的日志记录框架,它提供了灵活的日志配置和多种输出格式,便于...
Spring MVC、Spring Boot和Spring Data是Java开发领域中极为重要的框架,它们构成了现代企业级应用的基础。本资源集成了这三大框架,旨在提供一个基本零配置的开发环境,简化开发流程,提高效率。 Spring MVC是...
Spring MVC 是一个基于 Spring 框架的 Model-View-Controller (MVC) 模型的轻量级 Web 开发框架。它简化了在 Java 应用程序中开发 web 功能的过程,提供了一种模块化且松耦合的架构,支持多种视图技术,如 JSP、...
本资源是一个基于Maven构建的Spring4-MVC-Hibernate4的空框架,专为快速开发Java Web应用而设计。Spring MVC是Spring框架的一部分,用于构建Web应用程序的模型-视图-控制器(MVC)架构。Hibernate4则是一个强大的...
Spring MVC是Spring框架的一部分,它是一个用于构建Web应用程序的模型-视图-控制器(MVC)架构。这个压缩包包含了一整套Spring MVC运行所需的基础库和源代码,使得开发者无需单独寻找和集成各种依赖。下面将详细介绍...
Spring MVC 是一个基于Java的轻量级Web应用框架,它实现了Model-View-Controller(MVC)设计模式,主要用于处理Web请求和响应。...Spring MVC的灵活性和可扩展性使得它成为了许多企业级Web应用开发的首选框架。