日志
对于 Spring 日志是非常重要的依赖,因为:a)它是唯一的外部强制性的依赖;b)每个人都喜欢从他们使用的工具看到一些输出;c)Spring 结合很多其他工具都选择了日志依赖。应用开发者的一个目标是在一个应用程序的中心位置有统一的日志配置,包括所有的外部元件。而有太多可以选择的日志框架又增加了它的难度。
Spring 强制性的日志依赖 是 Jakarta Commons Logging API(JCL)。我们编译 JCL,也使 JCL Log对象对 Spring Framework 的扩展类可见。所有版本的 Spring 使用同样的日志库,这对于用户来说是很重要的:迁移就会变得容易,因为即使扩展Spring的应用程序仍然保留向后兼容性。我们达到之一目标的方式是使Spring中的一个模块明确地依赖于commons-logging(JCL的规范实现),然后在编译时使所有其他模块依赖于它。使用 Maven 为例,Spring的中心模块 spring-core 依赖了 commons-logging 。
commons-logging 的好处是你不需要任何东西就能让你的应用程序程序运行起来。它有一个运行时发现算法,该算法在classpath路径下寻找其他的日志框架并且使用它认为适合的(或者你可以告诉它你需要的是哪一个)。如果没有其他的日志框架存在,你可以从JDK(Java.util.logging 或者JUL 的简称)获得日志。在大多数情况下,你可以在控制台看到你的Spring 应用程序运行起来和并查看它的日志,这是很重要的。
使用 Log4j 1.2 或者 2.x
Log4j 1.2 已经停止维护,Log4j 2.3是最后一个 Java 6 兼容发行版,Log4j 2.x 最新的发行版需要Java 7 以上。
许多开发者出于配置和管理的目的使用Log4j作为日志框架。它是高效且成熟的,实践上在构建Spring时,在运行时也是使用的Log4j。Spring也提供了一些配置和初始化Log4j的工具,因此在一些模块中Log4j是可选的编译时依赖。
为了让 Log4j 1.2 与默认的JCL依赖一起工作,只需要将Log4j放入classpath,并提供一个配置文件(classpath根目录下的log4j.properties或log4j.xml)。Maven 依赖声明如下:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
以下是将日志写入控制台的log4j.properties的例子:
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
为了让 Log4j 2 与默认的JCL依赖一起工作,只需要将Log4j放入classpath,并提供一个配置文件(classpath根目录下的log4j2.properties、log4j2.xml 或其它支持的文件格式)。Maven 依赖声明如下:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
如果想使用SLF4J作为Log4j的代理,例如其它库默认使用SLF4J,需要神明以下依赖:
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
下面是一个日志写到控制台的log4j2.xml的例子:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="org.springframework.beans.factory" level="DEBUG"/>
<Root level="error">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
不使用 Commons Logging
不幸的是,commons-logging 的运行时日志框架发现算法方便了最终用户,但却是有问题的。如果你不想使用JCL的标准查找,有两种方法来关闭它:
- 通过 spring-core 模块排除依赖(因为它是唯一的显示依赖于 commons-logging 的模块);
- 依赖特殊的 commons-logging 依赖,用空的jar(更多的细节可以在SLF4J FAQ中找到)替换掉库。
排除 commons-logging,添加以下的内容到 dependencyManagement 部分:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
现在,这个应用程序可能运行不了,因为在类路径上没有实现的 JCL API,因此要修复它就必须提供一个新的日志框架。
使用 SLF4J 代理 Log4j 或 LogBack
Simple Logging Facade for Java (SLF4J) 是Spring其他库使用的流行API。它经常与LogBack( SLF4J API 的一个本地实现)一起使用。
SLF4J 可以与许多日志框架绑定,包括Log4j,它也做了反向工作:是其他日志框架和它自己之间的桥梁。因此在 Spring 中使用 SLF4J 时,你需要使用 SLF4J-JCL 桥接替换掉 commons-logging 的依赖。一旦你这么做了,Spring 调用日志就会调用 SLF4J API,因此如果在你的应用程序中的其他库使用这个API,那么你就需要有个地方配置和管理日志。
一个常见的选择就是桥接 Spring 和 SLF4J,提供显示的绑定 SLF4J 到Log4J 上。你需要支持一些依赖(排除现有的 commons-logging):JCL bridge,SLF4J 绑定 Log4J 和 Log4J 实现自身。在 Maven 中你可以这样做:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.0.RELEASE</version>
<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>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
对于SLF4J用户来说,一个更常见的选择是,使用更少的步骤和产生更少的依赖,那就是直接绑定 Logback。这消除了多余的绑定步骤,因为 Logback 直接实现了 SLF4J,因此你只需要依赖两个库jcl-over-slf4j and logback
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
使用 JUL (java.util.logging)
Commons Logging 当在classpath中未发现log4j时,会默认代理 JUL。所以不需要建立特殊的依赖。