2. Spring 框架简介

Spring 框架是一个 Java 平台,为开发 Java 应用程序提供全面的基础架构支持。 Spring 处理基础结构,因此您可以专注于应用程序。

Spring 使您能够从“普通的 Java 对象”(POJO)构建应用程序,并将企业服务非侵入性地应用于 POJO。此功能适用于 Java SE 编程模型以及全部和部分 Java EE。

作为应用程序开发人员,您如何从 Spring 平台中受益的示例:

  • 使 Java 方法在数据库事务中执行,而不必处理事务 API。

  • 使本地 Java 方法成为 HTTP 端点,而不必处理 Servlet API。

  • 使本地 Java 方法成为消息处理程序,而不必处理 JMS API。

  • 使本地 Java 方法成为 Management 操作,而不必处理 JMX API。

2.1 依赖注入和控制反转

Java 应用程序(一种宽松的术语,其范围从受约束的嵌入式应用程序到 n 层服务器端企业级应用程序),通常由协作形成适当应用程序的对象组成。因此,应用程序中的对象彼此具有依赖关系。

尽管 Java 平台提供了丰富的应用程序开发功能,但它缺乏将基本构建块组织成一个连贯的整体的方法,而将任务留给了架构师和开发人员。尽管您可以使用诸如* Factory Abstract Factory Builder Decorator Service Locator *之类的设计模式来构成组成应用程序的各种类和对象实例,但是这些模式仅是:给出最佳名称的最佳做法,并描述该模式的作用,应用方式,解决的问题等等。模式是形式化的最佳实践,您必须在应用程序中实现自己。

Spring 框架控制反转(IoC)组件通过提供一种形式化的方法来将不同的组件组成一个可以正常使用的应用程序,从而解决了这一问题。 Spring 框架将形式化的设计模式编码为一流的对象,您可以将其集成到自己的应用程序中。许多组织和机构都以这种方式使用 Spring Framework 来设计健壮的,“可维护的”应用程序。

Background

问题是,控制权的哪些方面是反转的?” Martin Fowler 在 2004 年提出了有关控制反转(IoC)在他的网站上的问题。Fowler 建议重命名该原理,使其更加不言自明,并提出了依赖注入

2.2 框架模块

Spring 框架包含组织为约 20 个模块的功能。这些模块分为核心容器,数据访问/集成,Web,AOP(面向方面的编程),检测,消息传递和测试,如下图所示。

图 2.1. Spring 框架概述

spring overview

以下各节列出了每个功能的可用模块,以及其工件名称和它们涵盖的主题。工件名称与依赖 Management 工具中使用的*工件 ID *相关。

2.2.1 核心容器

Core Containerspring-corespring-beansspring-contextspring-context-supportspring-expression(Spring 表达语言)模块组成。

spring-corespring-beans模块提供框架的基本部分,包括 IoC 和依赖注入功能。 BeanFactory是工厂模式的复杂实现。它消除了对编程单例的需求,并允许您将依赖项的配置和规范与实际程序逻辑脱钩。

Context(spring-context)模块构建在核心和 bean 类模块提供的坚实基础上:这是一种以类似于 JNDI 注册表的框架样式方式访问对象的方法。 Context 模块从 Beans 模块继承其功能,并增加了对国际化(例如,使用资源束),事件传播,资源加载以及通过 Servlet 容器透明创建上下文的支持。上下文模块还支持 Java EE 功能,例如 EJB,JMX 和基本远程处理。 ApplicationContext接口是上下文模块的焦点。 spring-context-support支持将常见的第三方库集成到 Spring 应用程序上下文中以进行缓存(EhCache,Guava,JCache),邮件(JavaMail),调度(CommonJ,Quartz)和模板引擎(FreeMarker,JasperReports,Velocity)。

spring-expression模块提供了功能强大的Expression Language,用于在运行时查询和操作对象图。它是对 JSP 2.1 规范中指定的统一表达语言(统一 EL)的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组,集合和索引器,逻辑和算术运算符,命名变量以及按名称从 Spring 的 IoC 容器中检索对象的内容。它还支持列表投影和选择以及常见的列表聚合。

2.2.2 AOP 和检测

spring-aop模块提供了AOP Alliance 兼容的面向方面的编程实现,例如,您可以定义方法拦截器和切入点,以干净地解耦实现应分离功能的代码。使用源级元数据功能,您还可以将行为信息以类似于.NET 属性的方式合并到代码中。

单独的spring-aspects模块提供与 AspectJ 的集成。

spring-instrument模块提供了在某些应用程序服务器中使用的类检测支持和类加载器实现。 spring-instrument-tomcat模块包含 Spring 的 Tomcat 的检测代理。

2.2.3 Messaging

Spring Framework 4 包含一个spring-messaging模块,该模块具有来自* Spring Integration *项目的关键抽象,例如MessageMessageChannelMessageHandler等,这些模块可作为基于消息的应用程序的基础。该模块还包括一组 Comments,用于将消息 Map 到方法,类似于基于 Spring MVCComments 的编程模型。

2.2.4 数据访问/集成

“数据访问/集成”层由 JDBC,ORM,OXM,JMS 和事务模块组成。

spring-jdbc模块提供了JDBC-抽象层,从而无需进行繁琐的 JDBC 编码和解析数据库供应商特定的错误代码。

spring-tx模块支持程序性和声明性 TransactionManagement,以实现实现特殊接口的类以及所有 POJO(普通的 Java 老式对象)

spring-orm模块为流行的object-relational mapping API 提供集成层,包括JPAJDOHibernate。使用spring-orm模块,您可以将所有这些 O/RMap 框架与 Spring 提供的所有其他功能结合使用,例如前面提到的简单的声明式事务 Management 功能。

spring-oxm模块提供了一个支持Object/XML mapping实现的抽象层,例如 JAXB,Castor,XMLBeans,JiBX 和 XStream。

spring-jms模块(Java 消息服务)包含用于生成和使用消息的功能。从 Spring Framework 4.1 开始,它提供了与spring-messaging模块的集成。

2.2.5 Web

  • Web *层由spring-webspring-webmvcspring-websocketspring-webmvc-portlet模块组成。

spring-web模块提供了面向 Web 的基本集成功能,例如 Multipart 文件上传功能以及使用 Servlet 侦听器和面向 Web 的应用程序上下文对 IoC 容器进行初始化。它还包含 HTTPClient 端和 Spring 远程支持的 Web 相关部分。

spring-webmvc模块(也称为* Web-Servlet *模块)包含 Spring 的 model-view-controller(MVC)和针对 Web 应用程序的 REST Web Services 实现。 Spring 的 MVC 框架在域模型代码和 Web 表单之间提供了清晰的分隔,并与 Spring 框架的所有其他功能集成在一起。

spring-webmvc-portlet模块(也称为* Web-Portlet *模块)提供了可在 Portlet 环境中使用的 MVC 实现,并镜像了基于 Servlet 的spring-webmvc模块的功能。

2.2.6 Test

spring-test模块通过 JUnit 或 TestNG 支持 Spring 组件的unit testingintegration testing。它提供了 Spring ApplicationContextloading和那些上下文的caching。它还提供了mock objects,可用于隔离测试代码。

2.3 使用场景

从在资源受限的设备上运行的嵌入式应用程序到使用 Spring 的事务 Management 功能和 Web 框架集成的成熟的企业应用程序,以前描述的构建模块使 Spring 在许多情况下成为逻辑上的选择。

图 2.2. 典型的成熟 Spring Web 应用程序

overview full

Spring 的声明式事务 Management 功能使 Web 应用程序具有完全事务性,就像使用 EJB 容器 Management 的事务一样。您所有的自定义业务逻辑都可以通过简单的 POJO 来实现,并由 Spring 的 IoC 容器进行 Management。其他服务包括独立于 Web 层的对发送电子邮件和验证的支持,使您可以选择在何处执行验证规则。 Spring 的 ORM 支持与 JPA,Hibernate 和 JDO 集成在一起;例如,在使用 Hibernate 时,您可以 continue 使用现有的 Map 文件和标准的 Hibernate SessionFactory配置。表单控制器将 Web 层与域模型无缝集成,从而无需ActionForms或其他将 HTTP 参数转换为域模型值的类。

图 2.3. 使用第三方 Web 框架的 Spring 中间层

概述第三方网站

有时情况不允许您完全切换到其他框架。 Spring 框架不会强制您使用其中的所有内容;它不是一个“全有或全无”的解决方案。使用 Struts,Tapestry,JSF 或其他 UI 框架构建的现有前端可以与基于 Spring 的中间层集成,从而可以使用 Spring 事务功能。您只需要使用ApplicationContext连接业务逻辑并使用WebApplicationContext来集成您的 Web 层。

图 2.4. 远程使用场景

overview remoting

当您需要通过 Web 服务访问现有代码时,可以使用 Spring 的Hessian-Burlap-Rmi-JaxRpcProxyFactory类。启用对现有应用程序的远程访问并不困难。

图 2.5. EJB-包装现有的 POJO

overview ejb

Spring 框架还为 Enterprise JavaBean 提供了访问和抽象层,使您可以重用现有的 POJO,并将它们包装在 Stateless 会话 Bean 中,以用于可能需要声明式安全性的可伸缩,故障安全的 Web 应用程序中。

2.3.1 依赖性 Management 和命名约定

依赖 Management 和依赖注入是不同的东西。为了将 Spring 的这些不错的功能(例如依赖注入)引入到您的应用程序中,您需要组装所需的所有库(jar 文件),并在运行时以及可能在编译时将它们放入 Classpath。这些依赖项不是注入的虚拟组件,而是文件系统中的物理资源(通常)。依赖项 Management 的过程包括查找那些资源,存储它们并将它们添加到 Classpath 中。依赖关系可以是直接的(例如,我的应用程序在运行时依赖于 Spring),也可以是间接的(例如,我的应用程序依赖于commons-dbcp,而commons-pool依赖)。间接依赖关系也称为“传递性”,最难以识别和 Management 的是那些依赖关系。

如果要使用 Spring,则需要获取包含所需 Spring 片段的 jar 库的副本。为了简化操作,Spring 被打包为一组模块,这些模块尽可能地分隔了依赖关系,例如,如果您不想编写 Web 应用程序,则不需要 spring-web 模块。要在本指南中引用 Spring 库模块,我们使用简写命名约定spring-*spring-*.jar,,其中*表示模块的简称(例如spring-corespring-webmvcspring-jms等)。您实际使用的 jar 文件名通常是与版本号连接的模块名称(例如* spring-core-4.3.21.RELEASE.jar *)。

Spring Framework 的每个发行版都会将工件发布到以下位置:

  • Maven Central 是 Maven 查询的默认存储库,不需要任何特殊配置即可使用。 Spring 依赖的许多常见库也可以从 Maven Central 中获得,并且 Spring 社区的很大一部分都使用 Maven 进行依赖项 Management,因此这对他们来说很方便。这里的罐子的名称格式为spring-*-<version>.jar,而 Maven groupId 为org.springframework

  • 在专门为 Spring 托管的公共 Maven 存储库中。除了最终的 GA 版本外,该存储库还托管开发快照和里程碑。 jar 文件的名称与 Maven Central 的格式相同,因此这是使 Spring 开发版本与部署在 Maven Central 中的其他库一起使用的有用位置。该存储库还包含 Binding 分发 zip 文件,该文件包含 Binding 在一起以方便下载的所有 Spring jar。

因此,您需要决定的第一件事是如何 Management 依赖项:我们通常建议使用自动化系统,例如 Maven,Gradle 或 Ivy,但是您也可以通过自己下载所有 jar 来手动进行操作。

在下面,您将找到 Spring 构件的列表。有关每个模块的更完整说明,请参见第 2.2 节“框架模块”

表 2.1. Spring Framework 工件

GroupIdArtifactIdDescription
org.springframeworkspring-aop基于代理的 AOP 支持
org.springframeworkspring-aspects基于 AspectJ 的方面
org.springframeworkspring-beansBean 支持,包括 Groovy
org.springframeworkspring-context应用程序上下文运行时,包括调度和远程处理抽象
org.springframeworkspring-context-support用于将通用第三方库集成到 Spring 应用程序上下文中的支持类
org.springframeworkspring-core其他许多 Spring 模块使用的核心 Util
org.springframeworkspring-expressionSpring 表达语言(SpEL)
org.springframeworkspring-instrument用于 JVM 引导的工具代理
org.springframeworkspring-instrument-tomcatTomcat 的检测代理
org.springframeworkspring-jdbcJDBC 支持包,包括数据源设置和 JDBC 访问支持
org.springframeworkspring-jmsJMS 支持包,包括用于发送/接收 JMS 消息的帮助程序类
org.springframeworkspring-messaging支持消息传递体系结构和协议
org.springframeworkspring-orm对象/关系 Map,包括 JPA 和 Hibernate 支持
org.springframeworkspring-oxmObject/XML Mapping
org.springframeworkspring-test支持单元测试和集成测试 Spring 组件
org.springframeworkspring-tx事务基础结构,包括 DAO 支持和 JCA 集成
org.springframeworkspring-web基本的 Web 支持,包括 WebClient 端和基于 Web 的远程处理
org.springframeworkspring-webmvcServlet 堆栈的基于 HTTP 的 Model-View-Controller 和 REST 端点
org.springframeworkspring-webmvc-portlet在 Portlet 环境中使用的 MVC 实现
org.springframeworkspring-websocketWebSocket 和 SockJS 基础结构,包括 STOMP 消息传递支持

Spring 依赖关系并取决于 Spring

尽管 Spring 为各种企业和其他外部工具提供了集成和支持,但它有意地将其强制性依赖项保持在绝对最低限度:您不必为了自动地找到和下载(甚至自动)大量的 jar 库而可以将 Spring 用于简单的用例。对于基本的依赖项注入,只有一个强制性的外部依赖项,即日志记录(有关日志记录选项的详细说明,请参见下文)。

接下来,我们概述配置依赖于 Spring 的应用程序所需的基本步骤,首先使用 Maven,然后使用 Gradle,最后使用 Ivy。在所有情况下,如果不清楚,请参阅依赖 Management 系统的文档或查看一些示例代码-Spring 本身在构建时使用 Gradle 来 Management 依赖关系,而我们的示例大多使用 Gradle 或 Maven。

Maven 依赖 Management

如果您使用Maven进行依赖性 Management,则甚至无需显式提供日志记录依赖性。例如,要创建应用程序上下文并使用依赖项注入来配置应用程序,您的 Maven 依赖项将如下所示:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.21.RELEASE</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

而已。请注意,如果您不需要针对 Spring API 进行编译,则可以将范围声明为运行时,这通常是基本依赖项注入用例的情况。

上面的示例适用于 Maven Central 存储库。要使用 Spring Maven 存储库(例如用于里程碑或开发人员快照),您需要在 Maven 配置中指定存储库位置。完整版本:

<repositories>
    <repository>
        <id>io.spring.repo.maven.release</id>
        <url>http://repo.spring.io/release/</url>
        <snapshots><enabled>false</enabled></snapshots>
    </repository>
</repositories>

For milestones:

<repositories>
    <repository>
        <id>io.spring.repo.maven.milestone</id>
        <url>http://repo.spring.io/milestone/</url>
        <snapshots><enabled>false</enabled></snapshots>
    </repository>
</repositories>

对于快照:

<repositories>
    <repository>
        <id>io.spring.repo.maven.snapshot</id>
        <url>http://repo.spring.io/snapshot/</url>
        <snapshots><enabled>true</enabled></snapshots>
    </repository>
</repositories>

Maven“物料 Lists”依赖性

使用 Maven 时,可能会偶然混合使用不同版本的 Spring JAR。例如,您可能会发现第三方库或另一个 Spring 项目将传递性依赖项引入了较旧的发行版。如果您忘记自己明确声明直接依赖项,则可能会出现各种意外问题。

为了克服这些问题,Maven 支持“物料 Lists”(BOM)依赖项的概念。您可以在dependencyManagement部分中导入spring-framework-bom,以确保所有 spring 依赖项(直接和传递)都处于同一版本。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>4.3.21.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

使用 BOM 的另一个好处是,根据 Spring Framework 工件,您不再需要指定<version>属性:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
    </dependency>
<dependencies>

Gradle 依赖性 Management

要将 Spring 存储库与Gradle构建系统一起使用,请在repositories部分中包含相应的 URL:

repositories {
    mavenCentral()
    // and optionally...
    maven { url "http://repo.spring.io/release" }
}

您可以根据需要将repositories URL 从/release更改为/milestone/snapshot。一旦配置了存储库,您就可以按照通常的 Gradle 方式声明依赖项:

dependencies {
    compile("org.springframework:spring-context:4.3.21.RELEASE")
    testCompile("org.springframework:spring-test:4.3.21.RELEASE")
}

Ivy 依赖 Management

如果您更喜欢使用Ivy来 Management 依赖项,则可以使用类似的配置选项。

要将 Ivy 配置为指向 Spring 存储库,请将以下解析器添加到ivysettings.xml

<resolvers>
    <ibiblio name="io.spring.repo.maven.release"
            m2compatible="true"
            root="http://repo.spring.io/release/"/>
</resolvers>

您可以根据需要将root URL 从/release/更改为/milestone//snapshot/

配置完成后,您可以按通常的方式添加依赖项。例如(在ivy.xml中):

<dependency org="org.springframework"
    name="spring-core" rev="4.3.21.RELEASE" conf="compile->runtime"/>

分发 Zip 文件

尽管建议使用支持依赖关系 Management 的构建系统来获取 Spring Framework,但是仍然可以下载发行版 zip 文件。

发行版 zip 发布到 Spring Maven 仓库(这只是为了我们的方便,您不需要 Maven 或任何其他构建系统即可下载它们)。

要下载分发 zip,请使用 Web 浏览器打开http://repo.spring.io/release/org/springframework/spring,然后为所需版本选择适当的子文件夹。分发文件以-dist.zip结尾,例如 spring-framework-{spring-version} -RELEASE-dist.zip。还发布了milestonessnapshots的发行版。

2.3.2 Logging

日志记录对于 Spring 是非常重要的依赖项,因为* a)是唯一的强制性外部依赖项, b)每个人都希望从他们使用的工具中看到一些输出,并且 c)* Spring 集成了许多其他工具所有这些还都选择了日志记录依赖性。应用程序开发人员的目标之一通常是在整个应用程序(包括所有外部组件)的中央位置配置统一日志记录。由于日志记录框架有很多选择,所以这比以前要困难的多。

Spring 中的强制日志记录依赖项是 Jakarta Commons Logging API(JCL)。我们针对 JCL 进行编译,还使扩展 Spring 框架的类可以看到 JCL Log对象。对用户来说重要的是,所有版本的 Spring 都使用相同的日志库:迁移很容易,因为即使使用扩展 Spring 的应用程序也可以保留向后兼容性。我们这样做的方法是使 Spring 中的模块之一显式依赖commons-logging(JCL 的规范实现),然后使所有其他模块在编译时依赖该模块。例如,如果您使用的是 Maven,并且想知道您对commons-logging的依赖在哪里,那么它来自 Spring,特别是来自名为spring-core的中央模块。

commons-logging的好处是您不需要其他任何东西即可使您的应用程序正常工作。它具有一种运行时发现算法,该算法在 Classpath 上众所周知的位置查找其他日志记录框架,并使用它认为合适的框架(或者您可以告诉它是否需要)。如果没有其他可用的东西,那么仅从 JDK(简称 java.util.logging 或 JUL)就可以得到漂亮的日志。您应该发现您的 Spring 应用程序可以正常工作,并且在大多数情况下可以开箱即用地登录到控制台,这很重要。

使用 Log4j 1.2 或 2.x

Note

Log4j 1.2 同时处于停产状态。此外,Log4j 2.3 是最新的 Java 6 兼容版本,而较新的 Log4j 2.x 发行版则需要 Java 7.

许多人使用Log4j作为用于配置和 Management 目的的日志记录框架。它高效且完善,事实上,这是我们在构建 Spring 时在运行时使用的。 Spring 还提供了一些 Util 来配置和初始化 Log4j,因此在某些模块中,它对 Log4j 具有可选的编译时依赖性。

要使 Log4j 1.2 与默认 JCL 依赖项(commons-logging)一起使用,您需要做的就是将 Log4j 放在 Classpath 上,并为其提供配置文件(在 Classpath 的根目录中为log4j.propertieslog4j.xml)。因此,对于 Maven 用户,这是您的依赖项声明:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.21.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.x 与 JCL 一起使用,您所需要做的就是将 Log4j 放在 Classpath 上,并为其提供配置文件(log4j2.xmllog4j2.properties或其他支持的配置格式)。对于 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 API 中的运行时发现算法虽然对最终用户很方便,但却可能会带来问题。如果您想避免 JCL 的标准查找,基本上有两种方法可以将其关闭:

  • spring-core模块中排除依赖项(因为它是唯一明确依赖commons-logging的模块)

  • 依赖于一个特殊的commons-logging依赖关系,该依赖关系用一个空的 jar 替换库(更多详细信息可以在SLF4J FAQ中找到)

要排除公共日志记录,请将以下内容添加到您的dependencyManagement部分:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.21.RELEASE</version>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

现在,由于在 Classpath 上没有 JCL API 的实现,该应用程序当前已被破坏,因此要修复该应用程序,必须提供一个新的应用程序。在下一部分中,我们将向您展示如何使用 SLF4J 提供 JCL 的替代实现。

将 SLF4J 与 Log4j 或 Logback 一起使用

Java 的简单日志记录外观(SLF4J)是由 Spring 常用的其他库使用的流行 API。它通常与Logback一起使用,Logback是 SLF4J API 的本机实现。

SLF4J 提供了对许多常见日志记录框架(包括 Log4j)的绑定,并且它的作用相反:在其他日志记录框架与其自身之间的 bridge 梁。因此,要将 SLF4J 与 Spring 一起使用,您需要用 SLF4J-JCLbridge 替换commons-logging依赖项。完成此操作后,Spring 内的日志记录调用将转换为对 SLF4J API 的日志记录调用,因此,如果应用程序中的其他库使用该 API,那么您就可以在一个地方配置和 Management 日志记录。

常见的选择可能是将 Springbridge 到 SLF4J,然后提供从 SLF4J 到 Log4j 的显式绑定。您需要提供一些依赖项(并排除现有的commons-logging):JCLbridge,绑定到 Log4j 的 SLF4j 以及 Log4j 提供程序本身。在 Maven 中,您将像这样

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.21.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.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

在 SLF4J 用户中,更常见的选择是直接绑定到Logback,该步骤使用更少的步骤并生成更少的依赖项。因为 Logback 直接实现 SLF4J,所以省去了额外的绑定步骤,因此您只需要依赖两个库,即jcl-over-slf4jlogback):

<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)

如果没有在 Classpath 上检测到 Log4j,默认情况下 Commons Logging 将委派给java.util.logging。因此,不需要设置任何特殊的依赖关系:只需在独立应用程序(具有 JDK 级别的自定义或默认 JUL 设置)或应用程序服务器的日志系统(以及其系统范围内的 JUL 设置)。

在 WebSphere 上的 Commons Logging

Spring 应用程序可以在本身提供 JCL 实现的容器上运行,例如 IBM 的 WebSphere Application Server(WAS)。这本身不会引起问题,但是会导致需要了解两种不同的情况:

在“父先” ClassLoader 委托模型(WAS 的默认值)中,应用程序将始终使用服务器提供的 Commons Logging 版本,委派给 WAS 日志子系统(实际上基于 JUL)。应用程序提供的 JCL 变体,无论是标准的 Commons Logging 还是 JCL-over-SLF4Jbridge,都会与任何本地包含的日志提供程序一起被有效忽略。

使用“父辈”委托模型(常规 Servlet 容器中的默认值,但 WAS 上有显式配置选项),将选择应用程序提供的 Commons Logging 变体,从而使您能够设置本地包含的日志提供程序,例如您的应用程序中的 Log4j 或 Logback。如果没有本地日志提供程序,则默认情况下,常规的 Commons Logging 将委派给 JUL,从而像“父先”方案中一样有效地记录到 WebSphere 的日志子系统。

总而言之,我们建议在“父后”模型中部署 Spring 应用程序,因为它自然地允许本地提供者以及服务器的日志子系统。