Spring 简明教程

Spring - Quick Guide

Spring Framework - Overview

Spring 是一个最受欢迎的应用程序开发框架,用于企业级 Java。全世界数百万开发人员使用 Spring Framework 创建高性能、易于测试的代码,可以重复使用。

Spring Framework 是一个开源 Java 平台。它最初由 Rod Johnson 编写,并于 2003 年 6 月首次在 Apache 2.0 许可证下发布。

在大小和透明度方面,Spring 是轻量级的。Spring Framework 的基本版本大约为 2MB。

Spring Framework 的核心特性可以用在 Java 应用程序的开发中,不过有一些扩展是在 Java EE 平台基础之上构建 Web 应用程序的。Spring 框架的目标是让 J2EE 开发用起来更轻松,并通过启用基于 POJO 的编程模型来提升良好的编程实践。

Benefits of Using the Spring Framework

以下是使用 Spring Framework 的若干重要优势清单

  1. Spring 让开发人员能够使用 POJO 开发企业级应用程序。只使用 POJO 的优势在于,你不需要像应用程序服务器之类的 EJB 容器产品,但你有权只使用强大的 servlet 容器,例如 Tomcat 或一些商业产品。

  2. Spring 按照模块化方式组织。即使包和类的数量很大,你只需要关注自己需要的那些,而忽略剩下的。

  3. Spring 不会重新发明轮子,相反,它真正利用了现有的技术,如多个 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,以及其他视图技术。

  4. 测试用 Spring 写入的应用程序很简单,因为依赖于环境的代码移到了这个框架中。此外,通过使用 JavaBean 类型的 POJO,更易于使用依赖项注入来注入测试数据。

  5. Spring 的 Web 框架是一个设计良好的 Web MVC 框架,它为 Struts 或其他过度设计或不受欢迎的 Web 框架之类的 Web 框架提供了极佳的替代方案。

  6. Spring 提供一个便利的 API,用于将特定技术的异常(例如 JDBC、Hibernate 或 JDO 生成的异常)转化为一致的、未经检查的异常。

  7. 轻量型 IoC 容器倾向于轻量,尤其是与 EJB 容器相比。这有益于在内存和 CPU 资源有限的计算机上开发和部署应用程序。

  8. Spring 提供一个一致的事务管理界面,该界面可以向下扩展到本地事务(例如,使用单个数据库),并向上扩展到全局事务(例如,使用 JTA)。

Dependency Injection (DI)

最能与 Spring 联系起来的的技术是反转控制 Dependency Injection (DI) 的特性。 Inversion of Control (IoC) 是一个通用概念,可以使用多种不同的方式来表达。依赖关系注入只是反转控制的一个具体示例。

在编写复杂的 Java 应用程序时,应用程序类与其它的 Java 类应该尽可能独立,以提高在单元测试时独立于其他类来重复利用和测试这些类的可能性。依赖关系注入有助于将这些类粘合在一起,并同时保持它们的独立性。

依赖关系注入到底是什么?让我们分别看一下这两个词。这里的依赖部分转换成了两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一下第二部分,注入。它的全部含义是,类 B 将由 IoC 注入到类 A 中。

依赖关系注入可以通过向构造函数传递参数或通过使用 setter 方法而在构建后执行。由于依赖关系注入是 Spring 框架的核心,因此我们将在一个单独的章节中使用相关的示例来解释这个概念。

Aspect Oriented Programming (AOP)

Spring 的一个关键组件是 Aspect Oriented Programming (AOP) 框架。跨越应用程序多个点的功能被称为 cross-cutting concerns ,这些交叉关注点在概念上与应用程序的业务逻辑是分开的。包括日志记录、声明式事务、安全、缓存等在内,有各种常见良好的方面示例。

面向对象编程中的模块化关键单元是类,而在面向方面编程中模块化的单元是方面。依赖关系注入有助于将应用程序对象相互解耦,而面向方面编程有助于将交叉关注点与它们影响的对象解耦。

Spring 框架的 AOP 模块提供面向切面的编程实现,使你可以定义方法拦截器和切入点,以便按部就班地解耦应该分离的功能的实现代码。我们将在一个单独的章节中进一步讨论 Spring AOP 的概念。

Spring Framework - Architecture

Spring 可能是你所有企业应用程序的一站式商店。但是,Spring 是模块化的,它允许你选择和挑选哪些模块适用于你,而无需引入其余部分。以下部分提供了 Spring Framework 中所有可用模块的详细信息。

Spring Framework 提供了大约 20 个模块,它们可以根据应用程序 requirement 使用。

spring architecture

Core Container

Core Container 包含 Core、Beans、Context 和 Expression Language 模块,其详细信息如下 −

  1. Core 模块提供了框架的基本部分,包括 IoC 和依赖注入特性。

  2. Bean 模块提供了 BeanFactory,它是工厂模式的一个复杂的实现。

  3. Context 模块建立在 Core 和 Beans 模块提供的基础上,它是一种访问任何已定义和配置对象的介质。ApplicationContext 接口是 Context 模块的重点。

  4. SpEL 模块为查询和操作对象图提供了强大的表达式语言。

Data Access/Integration

数据访问/集成层包含 JDBC、ORM、OXM、JMS 和 Transaction 模块,其详细信息如下 −

  1. JDBC 模块提供 JDBC 抽象层,消除了对繁琐的 JDBC 相关编码的需求。

  2. ORM 模块为流行的对象关系映射 API 提供集成层,包括 JPA、JDO、Hibernate 和 iBatis。

  3. OXM 模块提供一个抽象层,它支持 JAXB、Castor、XMLBeans、JiBX 和 XStream 的对象/XML 映射实现。

  4. Java Messaging Service JMS 模块包含用于生成和使用消息的特性。

  5. Transaction 模块支持为实现特殊接口的类和你的所有 POJO 提供程序化和声明式事务管理。

Web

Web 层包含 Web、Web-MVC、Web-Socket 和 Web-Portlet 模块,其详细信息如下 −

  1. Web 模块提供了基本的面向 Web 的集成特性,例如多部分文件上传功能,以及使用 servlet 侦听器和面向 Web 的应用程序上下文初始化 IoC 容器。

  2. Web-MVC 模块包含 Spring 的 Model-View-Controller (MVC),用于 Web 应用程序。

  3. Web-Socket 模块为 Web 应用程序中基于 WebSocket 的客户端和服务器之间的双向通信提供了支持。

  4. Web-Portlet 模块提供在 portlet 环境中使用的 MVC 实现,并反映 Web-Servlet 模块的功能。

Miscellaneous

还有几个其他重要的模块,如 AOP、Aspect、Instrumentation、Web 和 Test 模块,其详细信息如下 −

  1. AOP 模块提供面向切面的编程实现,允许您定义方法拦截器和切入点,以清楚地分离实现应分离功能的代码。

  2. Aspects 模块提供 AspectJ 集成,这又是一个强大而成熟的 AOP 框架。

  3. Instrumentation 模块提供类检测支持和类加载器实现,可在某些应用程序服务器中使用。

  4. Messaging 模块为 STOMP 提供支持,后者是应用程序中使用的 WebSocket 子协议。它还支持注释编程模型,用于将 WebSocket 客户机路由和处理 STOMP 消息。

  5. Test 模块支持使用 JUnit 或 TestNG 框架测试 Spring 组件。

Spring - Environment Setup

本章将指导你如何准备一个开发环境来开始你使用 Spring Framework 的工作。它还将教你如何在设置 Spring Framework 之前在你的机器上设置 JDK、Tomcat 和 Eclipse −

Step 1 - Setup Java Development Kit (JDK)

你可以从 Oracle 的 Java 站点下载 SDK 的最新版本 − Java SE Downloads. 你在下载文件中可以找到安装 JDK 的说明,按照给定的说明进行安装和配置。最后设置 PATH 和 JAVA_HOME 环境变量以引用包含 java 和 javac 的目录,通常分别为 java_install_dir/bin 和 java_install_dir。

如果你正在运行 Windows 并在 C:\jdk1.6.0_15 中安装了 JDK,则需要在你的 C:\autoexec.bat 文件中放入以下行。

set PATH=C:\jdk1.6.0_15\bin;%PATH%
set JAVA_HOME=C:\jdk1.6.0_15

或者,在 Windows NT/2000/XP 中,你必须右键单击我的电脑,选择属性 → 高级 → 环境变量。然后,你将不得不更新 PATH 值并单击确定按钮。

在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 /usr/local/jdk1.6.0_15 中,并且你使用 C shell,则必须将以下内容放入你的 .cshrc 文件中。

setenv PATH /usr/local/jdk1.6.0_15/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.6.0_15

或者,如果你使用诸如 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio 这样的集成开发环境 (IDE),则必须编译并运行一个简单程序来确认 IDE 知道你在何处安装了 Java。否则,你必须按照 IDE 文档中给出的内容执行正确的设置。

Step 2 - Install Apache Common Logging API

你可以从 https://commons.apache.org/logging/ 下载 Apache Commons Logging API 的最新版本。下载安装后,将二进制发行版解压缩到方便的位置。例如,在 Windows 上的 C:\commons-logging-1.1.1,或在 Linux/Unix 上的 /usr/local/commons-logging-1.1.1。此目录将具有以下 jar 文件和其他支持文档等。

common logging files

确保正确设置此目录上的 CLASSPATH 变量,否则在运行应用程序时会遇到问题。

Step 3 - Setup Eclipse IDE

本教程中的所有示例都是使用 Eclipse IDE 编写的。因此,我们建议你应该在你机器上安装 Eclipse 的最新版本。

要安装 Eclipse IDE,请从 https://www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压缩到方便的位置。例如,在 Windows 上的 C:\eclipse,或在 Linux/Unix 上的 /usr/local/eclipse,最后适当设置 PATH 变量。

可以通过在 Windows 机器上执行以下命令启动 Eclipse,或者你只需双击 eclipse.exe

%C:\eclipse\eclipse.exe

可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −

$/usr/local/eclipse/eclipse

成功启动后,如果一切正常,它应该显示以下结果 −

eclipsehomepage

Step 4 - Setup Spring Framework Libraries

现在,如果一切正常,则可以继续在你的机器上设置 Spring 框架。以下是下载和安装框架的简单步骤。

  1. 选择是要在 Windows 还是 Unix 上安装 Spring,然后继续下一步以下载 Windows 的 .zip 文件和 Unix 的 .tz 文件。

  2. https://repo.spring.io/release/org/springframework/spring 下载 Spring 框架二进制文件的最新版本。

  3. 在编写本教程时, spring-framework-4.1.6.RELEASE-dist.zip 已下载到 Windows 机器上。解压下载的文件后,它会在 E:\spring 中给出以下目录结构。

spring directories

你将在目录 E:\spring\libs 中找到所有 Spring 库。确保正确设置此目录上的 CLASSPATH 变量,否则在运行应用程序时会遇到问题。如果你正在使用 Eclipse,则不需要设置 CLASSPATH,因为所有设置都将通过 Eclipse 完成。

一旦完成最后一步,你就可以继续在下一章中进入你的第一个 Spring 示例了。

Spring - Hello World Example

我们开始使用 Spring Framework 进行实际编程。在使用 Spring 框架编写第一个示例之前,你必须确保已正确设置 Spring 环境,如 Spring - Environment Setup 章节中所述。我们还假设你对 Eclipse IDE 有点了解。

现在让我们开始编写一个简单的 Spring 应用程序,它将打印“Hello World!”或任何其他基于 Spring Bean 配置文件中所做的配置的消息。

Step 1 - Create Java Project

第一步是使用 Eclipse IDE 创建一个简单的 Java 项目。遵循选项 File → New → Project ,最后从向导列表中选择向导 Java Project 。现在使用向导窗口将你的项目命名为 HelloSpring ,如下所示:

hello spring wizard

一旦你的项目成功创建,你将在 Project Explorer 中看到以下内容:

hello spring dir

Step 2 - Add Required Libraries

作为第二步,让我们在项目中添加 Spring Framework 和通用日志记录 API 库。为此,右键单击你的项目名称 HelloSpring ,然后遵循上下文菜单中提供的以下选项 Build Path → Configure Build Path ,以按如下所示显示 Java 构建路径窗口:

java build path

现在使用 Libraries 选项卡下的 Add External JARs 按钮从 Spring Framework 和 Common Logging 安装目录中添加以下核心 JAR:

  1. commons-logging-1.1.1

  2. spring-aop-4.1.6.RELEASE

  3. spring-aspects-4.1.6.RELEASE

  4. spring-beans-4.1.6.RELEASE

  5. spring-context-4.1.6.RELEASE

  6. spring-context-support-4.1.6.RELEASE

  7. spring-core-4.1.6.RELEASE

  8. spring-expression-4.1.6.RELEASE

  9. spring-instrument-4.1.6.RELEASE

  10. spring-instrument-tomcat-4.1.6.RELEASE

  11. spring-jdbc-4.1.6.RELEASE

  12. spring-jms-4.1.6.RELEASE

  13. spring-messaging-4.1.6.RELEASE

  14. spring-orm-4.1.6.RELEASE

  15. spring-oxm-4.1.6.RELEASE

  16. spring-test-4.1.6.RELEASE

  17. spring-tx-4.1.6.RELEASE

  18. spring-web-4.1.6.RELEASE

  19. spring-webmvc-4.1.6.RELEASE

  20. spring-webmvc-portlet-4.1.6.RELEASE

  21. spring-websocket-4.1.6.RELEASE

Step 3 - Create Source Files

现在让我们在 HelloSpring 项目下创建实际源文件。首先,我们需要创建一个名为 com.tutorialspoint 的包。为此,右键单击包资源管理器部分中的 src ,然后按照以下选项进行操作: New → Package

接下来,我们将在 com.tutorialspoint 包下创建 HelloWorld.javaMainApp.java 文件。

spring source files

以下是 HelloWorld.java 文件的内容 −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

以下是第二个文件 MainApp.java 的内容:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

关于主程序,需要注意以下两点:

  1. 第一步是创建一个应用程序上下文,我们在其中使用了框架 API ClassPathXmlApplicationContext() 。此 API 加载 Bean 配置文件,并最终根据提供的 API,负责创建和初始化所有对象,即配置中提到的 bean。

  2. 第二步用于使用已创建的上下文的 getBean() 方法获取所需的 bean。此方法使用 Bean ID 返回一个通用对象,该对象最终可以转换为实际对象。一旦你拥有一个对象,你就可以使用此对象调用任何类方法。

Step 4 - Create Bean Configuration File

你需要创建一个 Bean 配置文件,它是一个 XML 文件,充当将 Bean(即类)粘合在一起的水泥。需要在 src 目录下创建此文件,如下面的屏幕截图所示:

beans conf file

通常开发人员将此文件命名为 Beans.xml ,但你可以自由选择任何你喜欢的名称。你必须确保此文件在 CLASSPATH 中可用,并在创建应用程序上下文时在主应用程序中使用相同名称,如 MainApp.java 文件中所示。

Beans.xml 用于为不同的 bean 分配唯一 ID,并控制在不影响任何 Spring 源文件的情况下创建具有不同值的对象。例如,使用以下文件,你可以为“message”变量传递任何值,并且可以在不影响 HelloWorld.java 和 MainApp.java 文件的情况下打印消息的不同值。让我们看看它是如何工作的。

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld">
      <property name = "message" value = "Hello World!"/>
   </bean>

</beans>

当 Spring 应用程序加载到内存中时,Framework 利用上述配置文件创建定义的所有 bean,并根据 <bean> 标记中定义的内容为它们分配一个唯一 ID。你可以使用 <property> 标记来传递在创建对象时使用的不同变量的值。

Step 5 - Running the Program

一旦你完成了源和 bean 配置文件的创建,你就可以进行此步骤,即编译和运行你的程序。为此,保持 MainApp.Java 文件选项卡处于活动状态,并使用 Eclipse IDE 中提供的 Run 选项或使用 Ctrl + F11 来编译和运行你的 MainApp 应用程序。如果你的应用程序一切正常,它将在 Eclipse IDE 的控制台中打印以下消息:

Your Message : Hello World!

恭喜你,你已成功创建你的第一个 Spring 应用程序。你可以通过更改“message”属性的值并保持两个源文件不变来查看上述 Spring 应用程序的灵活性。

Spring - IoC Containers

Spring 容器是 Spring Framework 的核心。容器将创建对象,将它们连接在一起,配置它们,并管理它们从创建到销毁的整个生命周期。Spring 容器使用 DI 来管理构成应用程序的组件。这些对象称为 Spring Bean,我们将在下一章中讨论它们。

容器通过读取提供的配置元数据来获取有关实例化、配置和组装对象的指令。该配置元数据可由 XML、Java 注释或 Java 代码表示。下图展示了 Spring 的工作原理的概述图。Spring IOC 容器利用 Java POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

spring ioc container

Spring 提供了下列两种不同类型的容器。

Sr.No.

Container & Description

1

Spring BeanFactory Container 这是最简单的容器,它提供对 DI 的基本支持,且由 org.springframework.beans.factory.BeanFactory 接口定义。为了向大量的与 Spring 集成的第三方框架提供向后兼容性,BeanFactory 及相关接口(例如 BeanFactoryAware、InitializingBean、DisposableBean)在 Spring 中仍然存在。

2

Spring ApplicationContext Container 该容器增加了更多的特定于企业的功能,例如从属性文件中解析文本消息以及将应用程序事件发布到感兴趣的事件侦听器的功能。该容器由 org.springframework.context.ApplicationContext 接口定义。

ApplicationContext 容器包含 BeanFactory 容器的所有功能,因此通常建议优于 BeanFactory。对于数据量和速度很重要的轻量级应用程序(如移动设备或基于小应用程序的应用程序),仍然可以使用 BeanFactory。

Spring - Bean Definition

构成应用程序主干且由 Spring IOC 容器管理的对象称为 beans 。Bean 是由 Spring IOC 容器实例化、组装和管理的对象。这些 Bean 是使用你提供给容器的配置元数据创建的。例如,在 XML <bean/> 定义中(你在前面章节中已经见过)。

Bean 定义包含 configuration metadata 名称的信息,其中需要容器知道以下内容:

  1. 如何创建 Bean

  2. Bean’s lifecycle details

  3. Bean’s dependencies

所有以上的配置元数据都转换为一组下面的属性,该组属性构成每个 Bean 定义。

Sr.No.

Properties & Description

1

class 此属性是必需的,并指定用于创建 Bean 的 Bean 类。

2

name 此属性唯一地指定 Bean 标识符。在基于 XML 的配置元数据中,使用 id 和/或 name 属性指定 Bean 标识符。

3

scope 此属性指定从特定 Bean 定义创建对象的范围,并且将在 Bean 范围章节讨论。

4

constructor-arg 此属性用于注入依赖项,并在后续章节讨论。

5

properties 此属性用于注入依赖项,并在后续章节讨论。

6

autowiring mode 此属性用于注入依赖项,并在后续章节讨论。

7

lazy-initialization mode 惰性初始化 Bean 告诉 IoC 容器首次请求 Bean 实例时,而非在启动时创建该实例。

8

initialization method 当容器已设置 Bean 上的所有必需属性之后,对回调的调用。将在 Bean 生命周期章节讨论该回调。

9

destruction method 当包含该 Bean 的容器被销毁时,对回调的使用。将在 Bean 生命周期章节讨论该回调。

Spring Configuration Metadata

Spring IOC 容器完全解除了此配置元数据实际编写的格式上的限制。向 Spring 容器提供配置元数据的三种重要方法如下:

  1. XML based configuration file.

  2. Annotation-based configuration

  3. Java-based configuration

您已经了解了如何向容器提供基于 XML 的配置元数据,但我们来看另一个基于 XML 的配置文件示例,其中包含不同的 bean 定义,包括延迟初始化、初始化方法和销毁方法 −

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- A simple bean definition -->
   <bean id = "..." class = "...">
      <!-- collaborators and configuration for this bean go here -->
   </bean>

   <!-- A bean definition with lazy init set on -->
   <bean id = "..." class = "..." lazy-init = "true">
      <!-- collaborators and configuration for this bean go here -->
   </bean>

   <!-- A bean definition with initialization method -->
   <bean id = "..." class = "..." init-method = "...">
      <!-- collaborators and configuration for this bean go here -->
   </bean>

   <!-- A bean definition with destruction method -->
   <bean id = "..." class = "..." destroy-method = "...">
      <!-- collaborators and configuration for this bean go here -->
   </bean>

   <!-- more bean definitions go here -->

</beans>

您可以查看 Spring Hello World Example 来了解如何定义、配置和创建 Spring Bean。

我们将在单独的一章中讨论基于注解的配置。它是有意在单独的章节中讨论的,因为我们希望您掌握一些其他重要的 Spring 概念,然后再开始使用带注解的 Spring 依赖项注入进行编程。

Spring - Bean Scopes

在定义 <bean> 时,您可以选择声明该 bean 的作用域。例如,要强制 Spring 在每次需要一个 bean 实例时生成一个新的 bean 实例,您应该将 bean 的作用域属性声明为 prototype 。类似地,如果您希望 Spring 在每次需要一个 bean 实例时返回同一个 bean 实例,您应该将 bean 的作用域属性声明为 singleton

Spring 框架支持以下五个作用域,其中三个仅在您使用 web 感知 ApplicationContext 时可用。

Sr.No.

Scope & Description

1

singleton 此作用域将 bean 定义作用域设置为每个 Spring IoC 容器(默认值)的一个实例。

2

prototype 此作用域将单个 bean 定义作用域设置为具有任意数量的对象实例。

3

request 此作用域将 bean 定义作用域设置为 HTTP 请求。仅在 web 感知 Spring ApplicationContext 的上下文中有效。

4

session 此作用域将 bean 定义作用域设置为 HTTP 会话。仅在 web 感知 Spring ApplicationContext 的上下文中有效。

5

global-session 此作用域将 bean 定义作用域设置为全局 HTTP 会话。仅在 web 感知 Spring ApplicationContext 的上下文中有效。

在本章中,我们将讨论前两个作用域,其余三个将在我们讨论 web 感知 Spring ApplicationContext 时进行讨论。

The singleton scope

如果将作用域设置为 singleton,则 Spring IoC 容器会为该 bean 定义所定义的对象创建恰好一个实例。此单个实例存储在这些 singleton bean 的缓存中,并且对该已命名 bean 的所有后续请求和引用都会返回缓存对象。

默认作用域始终是单例。但是,当您只需要一个 bean 实例时,可以如以下代码片段所示在 bean 配置文件中设置 scope * property to *singleton

<!-- A bean definition with singleton scope -->
<bean id = "..." class = "..." scope = "singleton">
   <!-- collaborators and configuration for this bean go here -->
</bean>

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容 −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

以下是 MainApp.java 文件的内容−

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.setMessage("I'm object A");
      objA.getMessage();

      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

以下是 singleton 作用域所需的配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" scope = "singleton">
   </bean>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

Your Message : I'm object A
Your Message : I'm object A

The prototype scope

如果将作用域设置为 prototype,则 Spring IoC 容器会在每次对特定 bean 发出请求时为该对象创建一个新的 bean 实例。一般而言,将 prototype 作用域用于所有有状态 bean,将 singleton 作用域用于无状态 bean。

要定义 prototype 作用域,可以在 bean 配置文件中将属性 scope 设置为 prototype ,如以下代码片段所示 −

<!-- A bean definition with prototype scope -->
<bean id = "..." class = "..." scope = "prototype">
   <!-- collaborators and configuration for this bean go here -->
</bean>

Example

让我们启动 Eclipse IDE 并按照以下步骤创建一个 Spring 应用程序 −

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

以下是 MainApp.java 文件的内容−

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.setMessage("I'm object A");
      objA.getMessage();

      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

以下是 prototype 作用域所需的配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" scope = "prototype">
   </bean>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

Your Message : I'm object A
Your Message : null

Spring - Bean Life Cycle

Spring Bean 的生命周期很容易理解。当实例化一个 Bean 时,可能需要执行一些初始化操作使其进入可用状态。同样,当不再需要 Bean 并从容器中移除时,可能需要进行一些清理操作。

尽管在 Bean 实例化和销毁之间的时间里有许多幕后活动列表,但本章只讨论两个重要的 Bean 生命周期回调方法,它们在 Bean 初始化和销毁时需要。

要为 Bean 定义设置和拆除操作,我们只需使用 initmethod 和/或 destroy-method 参数声明 <bean>。init-method 属性指定一个方法,该方法在实例化后立即在 Bean 上调用。类似地,destroymethod 指定一个方法,该方法在 bean 从容器中移除之前调用。

Initialization callbacks

org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法 −

void afterPropertiesSet() throws Exception;

因此,你可以简单地实现上述接口,初始化工作可以在 afterPropertiesSet() 方法中完成如下:

public class ExampleBean implements InitializingBean {
   public void afterPropertiesSet() {
      // do some initialization work
   }
}

在基于 XML 的配置文件元数据的情况下,你可以使用 init-method 属性指定具有 void 无参数签名的该方法的名称。例如 −

<bean id = "exampleBean" class = "examples.ExampleBean" init-method = "init"/>

下面的类定义 −

public class ExampleBean {
   public void init() {
      // do some initialization work
   }
}

Destruction callbacks

org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法 −

void destroy() throws Exception;

因此,你可以简单地实现上述接口,最终化工作可以在 destroy() 方法中完成如下:

public class ExampleBean implements DisposableBean {
   public void destroy() {
      // do some destruction work
   }
}

在基于 XML 的配置文件元数据的情况下,你可以使用 destroy-method 属性指定具有 void 无参数签名的该方法的名称。例如 −

<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>

下面的类定义 −

public class ExampleBean {
   public void destroy() {
      // do some destruction work
   }
}

如果你在一个非网络应用程序环境中使用 Spring 的 IoC 容器,例如在富客户端桌面环境中,你要向 JVM 注册一个关闭钩子。这样做可确保正常关闭,并在你的单例 Bean 上调用相关的销毁方法,以便释放所有资源。

建议不要使用 InitializingBean 或 DisposableBean 回调,因为 XML 配置在方法命名方面提供了很大的灵活性。

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容 −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy() {
      System.out.println("Bean will destroy now.");
   }
}

以下是 MainApp.java 文件的内容。这里你需要注册一个关闭钩子 registerShutdownHook() 方法,该方法在 AbstractApplicationContext 类中声明。这将确保正常关闭并调用相关的销毁方法。

package com.tutorialspoint;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

以下是 init 方法和 destroy 方法所需的配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" init-method = "init"
      destroy-method = "destroy">
      <property name = "message" value = "Hello World!"/>
   </bean>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

Bean is going through init.
Your Message : Hello World!
Bean will destroy now.

Default initialization and destroy methods

如果你有太多具有相同名称的初始化和/或销毁方法的 Bean,则无需在每个单独 Bean 上声明 init-methoddestroy-method 。相反,框架提供了使用 <beans> 元素上的 default-init-methoddefault-destroy-method 属性配置这种情况的灵活性,如下所示 −

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
   default-init-method = "init"
   default-destroy-method = "destroy">

   <bean id = "..." class = "...">
      <!-- collaborators and configuration for this bean go here -->
   </bean>

</beans>

Spring - Bean Post Processors

BeanPostProcessor 接口定义回调方法,您可以实现这些方法以提供自己的实例化逻辑、依赖关系解析逻辑等。您还可以在 Spring 容器完成 bean 的实例化、配置和初始化后实现一些自定义逻辑,方法是插入一个或多个 BeanPostProcessor 实现。

你可以配置多个 BeanPostProcessor 接口,并且可以通过设置 BeanPostProcessor 实现 Ordered 接口提供的 order 属性来控制这些 BeanPostProcessor 接口执行的顺序。

在 Bean(或对象)实例上运行 BeanPostProcessor,这意味着 Spring IoC 容器实例化一个 Bean 实例,然后 BeanPostProcessor 接口执行它们的工作。

ApplicationContext 会自动检测以 BeanPostProcessor 接口实现为定义的任何 bean,并注册这些 bean 作为后置处理器,然后由容器在 bean 创建时适时调用。

Example

以下示例展示如何在 ApplicationContext 的上下文中编写、注册和使用方法 BeanPostProcessor。

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld、InitHelloWorld 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容 −

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

这是一个实现 BeanPostProcessor 的非常基本的示例,该示例在任何 bean 初始化之前和之后输出一个 bean 名称。你可以在初始化 bean 的前后实现更复杂的逻辑,因为你可以同时在 post 处理器方法中访问 bean 对象。

以下为 InitHelloWorld.java 文件内容−

package com.tutorialspoint;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;

public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {

      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName)
      throws BeansException {

      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}

以下是 MainApp.java 文件的内容。在这里你需要注册 AbstractApplicationContext 类中声明的关机挂接 registerShutdownHook() 方法。这将确保正常关闭并调用相关的销毁方法。

package com.tutorialspoint;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

以下是 init 方法和 destroy 方法所需的配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"
      init-method = "init" destroy-method = "destroy">
      <property name = "message" value = "Hello World!"/>
   </bean>

   <bean class = "com.tutorialspoint.InitHelloWorld" />

</beans>

一旦你完成了创建源代码和 bean 配置文件,让我们运行该应用程序。如果你的应用程序一切正常,则将显示以下信息 −

BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.

Spring - Bean Definition Inheritance

一个 Bean 定义可以包含许多配置信息,包括构造函数参数、属性值,以及特定于容器的信息,比如初始化方法、静态工厂方法名,等等。

一个子 Bean 定义从父定义继承配置数据。子定义可以根据需要覆盖某些值,或添加其他值。

Spring Bean 定义继承与 Java 类继承无关,但继承概念是一样的。你可以将父 Bean 定义定义为模板,其他子 Bean 可以从中继承所需的配置。

使用基于 XML 的配置元数据时,可以通过使用 parent 属性来指示一个子 Bean 定义,指定父 Bean 作为该属性的值。

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld、HelloIndia 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是配置文件 Beans.xml ,我们在其中定义了“helloWorld”Bean,它具有两个属性 message1 和 message2。接下来“helloIndia”Bean 已被定义为“helloWorld”Bean 的子项,方法是使用 parent 属性。该子 Bean 原样继承 message2 属性,并覆盖 message1 属性并引入一个新的 message3 属性。

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld">
      <property name = "message1" value = "Hello World!"/>
      <property name = "message2" value = "Hello Second World!"/>
   </bean>

   <bean id ="helloIndia" class = "com.tutorialspoint.HelloIndia" parent = "helloWorld">
      <property name = "message1" value = "Hello India!"/>
      <property name = "message3" value = "Namaste India!"/>
   </bean>
</beans>

以下是 HelloWorld.java 文件的内容 −

package com.tutorialspoint;

public class HelloWorld {
   private String message1;
   private String message2;

   public void setMessage1(String message){
      this.message1 = message;
   }
   public void setMessage2(String message){
      this.message2 = message;
   }
   public void getMessage1(){
      System.out.println("World Message1 : " + message1);
   }
   public void getMessage2(){
      System.out.println("World Message2 : " + message2);
   }
}

以下是 HelloIndia.java 文件的内容 −

package com.tutorialspoint;

public class HelloIndia {
   private String message1;
   private String message2;
   private String message3;

   public void setMessage1(String message){
      this.message1 = message;
   }
   public void setMessage2(String message){
      this.message2 = message;
   }
   public void setMessage3(String message){
      this.message3 = message;
   }
   public void getMessage1(){
      System.out.println("India Message1 : " + message1);
   }
   public void getMessage2(){
      System.out.println("India Message2 : " + message2);
   }
   public void getMessage3(){
      System.out.println("India Message3 : " + message3);
   }
}

以下是 MainApp.java 文件的内容−

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
      objA.getMessage1();
      objA.getMessage2();

      HelloIndia objB = (HelloIndia) context.getBean("helloIndia");
      objB.getMessage1();
      objB.getMessage2();
      objB.getMessage3();
   }
}

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

World Message1 : Hello World!
World Message2 : Hello Second World!
India Message1 : Hello India!
India Message2 : Hello Second World!
India Message3 : Namaste India!

如果你在这里观察到,我们在创建“helloIndia”Bean 时没有传递 message2,但由于 Bean 定义继承,它已经传递了。

Bean Definition Template

你可以创建一个 Bean 定义模板,它可以在其他子 Bean 定义中使用,无需付出太多努力。在定义 Bean 定义模板时,你应该不要指定 class 属性,而应该指定 abstract 属性,并且应该使用 true 值指定 abstract 属性,如下面的代码片段所示 −

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "beanTeamplate" abstract = "true">
      <property name = "message1" value = "Hello World!"/>
      <property name = "message2" value = "Hello Second World!"/>
      <property name = "message3" value = "Namaste India!"/>
   </bean>

   <bean id = "helloIndia" class = "com.tutorialspoint.HelloIndia" parent = "beanTeamplate">
      <property name = "message1" value = "Hello India!"/>
      <property name = "message3" value = "Namaste India!"/>
   </bean>

</beans>

父 Bean,它本身无法实例化,因为它是不完整的,并且它还被明确标记为 abstract。当一个定义像这样抽象时,它只能作为一个纯模板 Bean 定义使用,它作为子定义的父定义。

Spring - Dependency Injection

每个基于 Java 的应用程序都有一些对象可以协同工作,以展示最终用户所看到的工作应用程序。在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类并使其独立于其他类进行单​​元测试的可能性。依赖注入(或有时称为连接)有助于将这些类粘合在一起,同时又保持它们独立性。

考虑您有一个包含文本编辑器组件的应用程序,并且您希望提供拼写检查。您的标准代码将如下所示 −

public class TextEditor {
   private SpellChecker spellChecker;

   public TextEditor() {
      spellChecker = new SpellChecker();
   }
}

我们在此处所做的是创建 TextEditor 和 SpellChecker 之间的依赖关系。在控制反转场景中,我们改为执行类似以下操作 −

public class TextEditor {
   private SpellChecker spellChecker;

   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
}

在这里,TextEditor 不应该担心 SpellChecker 实现。SpellChecker 将被独立实现,并在 TextEditor 实例化时提供给 TextEditor。此整个过程由 Spring 框架控制。

在此,我们从 TextEditor 中删除了全部控制权,并将其保存在其他地方(即 XML 配置文件),并且依赖项(即类 SpellChecker)正在通过 Class Constructor 注入到类 TextEditor 中。因此,依赖注入(DI)已经“反转”了控制流,因为您实际上已经将依赖委托给某个外部系统。

注入依赖关系的第二种方法是通过 TextEditor 类的 Setter Methods ,我们将在其中创建 SpellChecker 实例。此实例将用于调用 setter 方法来初始化 TextEditor 的属性。

因此,DI 以两种主要形式存在,以下两个小章节将用示例介绍它们 −

Sr.No.

依赖注入类型及说明

1

Constructor-based dependency injection 基于构造函数的 DI 在容器使用一些参数(每个参数表示对其他类的依赖关系)调用类构造函数时完成。

2

Setter-based dependency injection 基于 setter 的 DI 由容器在调用无参数构造函数或无参数静态工厂方法来实例化 bean 之后,通过在您的 bean 上调用 setter 方法来完成。

您可以混合使用基于构造函数的 DI 和基于 setter 的 DI,但一个好经验法则是对强制依赖关系使用构造函数参数,对可选依赖关系使用 setter。

使用 DI 原则的代码更简洁,当对象获得其依赖项时,解耦将更加有效。对象不会查找其依赖项,并且不知道依赖项的位置或类,而是 Spring 框架负责所有操作。

Spring - Injecting Inner Beans

众所周知,Java 内部类在其他类的范围内内定义,类似地, inner beans 是在另一个 bean 的范围内内定义的 bean。因此,<property/> 或 <constructor-arg/> 元素中的 <bean/> 元素被称为内部 bean,如下所示。

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "outerBean" class = "...">
      <property name = "target">
         <bean id = "innerBean" class = "..."/>
      </property>
   </bean>

</beans>

Example

让我们启动 Eclipse IDE 并按照以下步骤创建一个 Spring 应用程序 −

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 TextEditor、SpellChecker 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下为 TextEditor.java 文件的内容 −

package com.tutorialspoint;

public class TextEditor {
   private SpellChecker spellChecker;

   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }

   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

以下是另一个依赖类文件 SpellChecker.java 的内容 −

package com.tutorialspoint;

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }
}

以下是 MainApp.java 文件的内容−

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

以下是 Beans.xml 的配置文件,其中对基于 setter 的注入但使用 inner beans 进行了配置 −

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for textEditor bean using inner bean -->
   <bean id = "textEditor" class = "com.tutorialspoint.TextEditor">
      <property name = "spellChecker">
         <bean id = "spellChecker" class = "com.tutorialspoint.SpellChecker"/>
      </property>
   </bean>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.

Spring - Injecting Collection

您已经看到如何使用 Bean 配置文件中的 <property> 标记的 value 属性配置原始数据类型,以及使用 ref 属性配置对象引用。这两种情况都涉及将奇异值传递给 Bean。

现在,如果您想传递复数值,如 Java 集合类型(例如列表、集合、映射和属性),该怎么办。为了处理这种情况,Spring 提供了四种类型的集合配置元素,如下所示−

Sr.No

Element & Description

1

&lt;list&gt; 这有助于进行接线,即注入一个值列表,同时允许重复。

2

&lt;set&gt; 这有助于接线一组值,但没有任何重复。

3

&lt;map&gt; 这可用于注入名称-值对的集合,其中名称和值可以是任何类型。

4

&lt;props&gt; 这可用于注入名称-值对的集合,其中名称和值都是字符串。

您可以使用 <list> 或 <set> 来接线任何 java.util.Collection 的实现或 array

您将遇到两种情况:(a) 传递集合的直接值和 (b) 传递 Bean 引用作为集合元素之一。

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 JavaCollection 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 JavaCollection.java 文件的内容−

package com.tutorialspoint;
import java.util.*;

public class JavaCollection {
   List addressList;
   Set  addressSet;
   Map  addressMap;
   Properties addressProp;

   // a setter method to set List
   public void setAddressList(List addressList) {
      this.addressList = addressList;
   }

   // prints and returns all the elements of the list.
   public List getAddressList() {
      System.out.println("List Elements :"  + addressList);
      return addressList;
   }

   // a setter method to set Set
   public void setAddressSet(Set addressSet) {
      this.addressSet = addressSet;
   }

   // prints and returns all the elements of the Set.
   public Set getAddressSet() {
      System.out.println("Set Elements :"  + addressSet);
      return addressSet;
   }

   // a setter method to set Map
   public void setAddressMap(Map addressMap) {
      this.addressMap = addressMap;
   }

   // prints and returns all the elements of the Map.
   public Map getAddressMap() {
      System.out.println("Map Elements :"  + addressMap);
      return addressMap;
   }

   // a setter method to set Property
   public void setAddressProp(Properties addressProp) {
      this.addressProp = addressProp;
   }

   // prints and returns all the elements of the Property.
   public Properties getAddressProp() {
      System.out.println("Property Elements :"  + addressProp);
      return addressProp;
   }
}

以下是 MainApp.java 文件的内容−

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      JavaCollection jc=(JavaCollection)context.getBean("javaCollection");

      jc.getAddressList();
      jc.getAddressSet();
      jc.getAddressMap();
      jc.getAddressProp();
   }
}

以下是配置文件 Beans.xml ,其中包含对所有类型集合的配置−

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Definition for javaCollection -->
   <bean id = "javaCollection" class = "com.tutorialspoint.JavaCollection">

      <!-- results in a setAddressList(java.util.List) call -->
      <property name = "addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>

      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name = "addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </set>
      </property>

      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name = "addressMap">
         <map>
            <entry key = "1" value = "INDIA"/>
            <entry key = "2" value = "Pakistan"/>
            <entry key = "3" value = "USA"/>
            <entry key = "4" value = "USA"/>
         </map>
      </property>

      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name = "addressProp">
         <props>
            <prop key = "one">INDIA</prop>
            <prop key = "one">INDIA</prop>
            <prop key = "two">Pakistan</prop>
            <prop key = "three">USA</prop>
            <prop key = "four">USA</prop>
         </props>
      </property>
   </bean>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

List Elements :[INDIA, Pakistan, USA, USA]
Set Elements :[INDIA, Pakistan, USA]
ap Elements :{1 = INDIA, 2 = Pakistan, 3 = USA, 4 = USA}
Property Elements :{two = Pakistan, one = INDIA, three = USA, four = USA}

Injecting Bean References

以下 Bean 定义将帮助您了解如何将 Bean 引用注入为集合的元素之一。您甚至可以将引用和值混合在一起,如下面的代码片段所示−

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <!-- Bean Definition to handle references and values -->
   <bean id = "..." class = "...">

      <!-- Passing bean reference  for java.util.List -->
      <property name = "addressList">
         <list>
            <ref bean = "address1"/>
            <ref bean = "address2"/>
            <value>Pakistan</value>
         </list>
      </property>

      <!-- Passing bean reference  for java.util.Set -->
      <property name = "addressSet">
         <set>
            <ref bean = "address1"/>
            <ref bean = "address2"/>
            <value>Pakistan</value>
         </set>
      </property>

      <!-- Passing bean reference  for java.util.Map -->
      <property name = "addressMap">
         <map>
            <entry key = "one" value = "INDIA"/>
            <entry key = "two" value-ref = "address1"/>
            <entry key = "three" value-ref = "address2"/>
         </map>
      </property>
   </bean>

</beans>

要使用上述 Bean 定义,您需要以能够处理引用的方式定义您的 setter 方法。

Injecting null and empty string values

如果您需要传递一个空字符串作为值,那么您可以按如下方式传递−

<bean id = "..." class = "exampleBean">
   <property name = "email" value = ""/>
</bean>

前面的示例等效于 Java 代码:exampleBean.setEmail("")

如果您需要传递一个 NULL 值,那么您可以按如下方式传递−

<bean id = "..." class = "exampleBean">
   <property name = "email"><null/></property>
</bean>

前面的示例等价于 Java 代码:exampleBean.setEmail(null)

Spring - Beans Auto-Wiring

你已了解如何使用 <bean> 元素声明 bean,并使用 XML 配置文件中的 <constructor-arg> 和 <property> 元素注入 <bean>。

Spring 容器可以在不使用 <constructor-arg> 和 <property> 元素的情况下确定协作 bean 之间的关系,这有助于减少为大型基于 Spring 的应用程序编写的 XML 配置量。

Autowiring Modes

以下是自动装配模式,可以用于指示 Spring 容器对依赖项注入使用自动装配。你可以使用 <bean/> 元素的 autowire 属性来为 bean 定义指定 autowire 模式。

Sr.No

Mode & Description

1

*no*这是默认设置,表示不自动装配,而你应该使用显式的 bean 引用来进行装配。你不需要专门为此装配做任何事。这是你在依赖项注入一章中已经了解的内容。

2

byName 按属性名称自动装配。Spring 容器会查看 XML 配置文件中将 autowire 属性设置为 byName 的 bean 的属性。然后,它会尝试匹配并用配置中具有相同名称的 bean 装配其属性。

3

byType 按属性数据类型自动装配。Spring 容器查看 XML 配置文件中的自动装配属性设置为按类型装配的 Bean 的属性。然后它尝试匹配并连接属性,如果其 type 恰好与配置文件中 Bean 名称的其中一个匹配。如果存在多个这样的 Bean,则会引发致命异常。

4

constructor 与按类型装配类似,但类型适用于构造函数参数。如果在容器中没有恰好一个构造函数参数类型的 Bean,则会引发致命错误。

5

*自动检测*Spring 首先尝试通过构造函数自动装配来连接,如果不起作用,Spring 尝试按类型自动装配。

你可以使用 byTypeconstructor 自动装配模式来连接数组和其他类型集合。

Limitations with autowiring

当在整个项目中一致使用时,自动装配效果最好。如果通常不使用自动装配,开发人员仅将其用于连接一个或两个 Bean 定义可能会令人迷惑。尽管如此,自动装配可以显著减少指定属性或构造函数参数的需要,但你应在使用自动装配前考虑其局限性和缺点。

Sr.No.

Limitations & Description

1

Overriding possibility 你仍然可以使用 <constructor-arg> 和 <property> 设置来指定依赖,这将始终覆盖自动装配。

2

Primitive data types 你不能自动装配原始类型、字符串和类等所谓的简单属性。

3

Confusing nature 自动装配不像显式装配那么精确,所以如果可能,最好使用显式装配。

Spring - Annotation Based Configuration

从 Spring 2.5 开始,可以使用 annotations 配置依赖注入成为可能。因此,与其使用 XML 来描述 Bean 装配,你可以使用对相关类、方法或字段声明的注释将 Bean 配置移到组件类本身中。

注释注入在 XML 注入前执行。因此,对于通过两种方法连接的属性,后一种配置将覆盖前一种配置。

在 Spring 容器中,注释装配不会默认启用。因此,在使用基于注释的装配之前,我们需要在 Spring 配置文件中启用它。所以如果你想在你的 Spring 应用程序中使用任何注释,请考虑以下配置文件。

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context = "http://www.springframework.org/schema/context"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   <!-- bean definitions go here -->

</beans>

一旦 <context:annotation-config/> 被配置,你可以开始注释你的代码,以表明 Spring 应自动将值连接到属性、方法和构造函数中。让我们来看一些重要的注释以了解它们如何工作:-

Sr.No.

Annotation & Description

1

@Required @Required 注释适用于 Bean 属性设置器方法。

2

@Autowired @Autowired 注释可以适用于 Bean 属性设置器方法、非设置器方法、构造函数和属性。

3

@Qualifier @Qualifier 注释连同 @Autowired 可用于消除混乱,方法是指定将连接哪个确切的 Bean。

4

JSR-250 Annotations Spring 支持基于 JSR-250 的注释,其中包括 @Resource、@PostConstruct 和 @PreDestroy 注释。

Spring - Java Based Configuration

到目前为止,你知道我们如何使用 XML 配置文件配置 Spring Bean。如果你熟悉 XML 配置,那么真的没有必要学习如何继续基于 Java 的配置,因为你可以使用任何可用的配置来实现相同的结果。

基于 Java 的配置选项使你能够在没有 XML 的情况下编写大部分 Spring 配置,但借助本章中解释的几个基于 Java 的注释来实现。

@Configuration & @Bean Annotations

使用 @Configuration 注释类表示该类可被 Spring IoC 容器用作 Bean 定义的来源。 @Bean 注释告诉 Spring 一个使用 @Bean 注释的方法将返回一个对象,该对象应注册为 Spring 应用程序上下文中的 Bean。最简单的可能的 @Configuration 类如下所示:

package com.tutorialspoint;
import org.springframework.context.annotation.*;

@Configuration
public class HelloWorldConfig {
   @Bean
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

如上代码将等同于以下 XML 配置 -

<beans>
   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" />
</beans>

在此,用 @Bean 注释的方法名用作 bean ID,并且它创建并返回实际 bean。配置类可包含多个 @Bean 的声明。一旦定义了配置类,即可使用 AnnotationConfigApplicationContext 将它们加载并提供给 Spring 容器,如下所示 -

public static void main(String[] args) {
   ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class);

   HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
   helloWorld.setMessage("Hello World!");
   helloWorld.getMessage();
}

可加载各个配置类,如下所示 -

public static void main(String[] args) {
   AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

   ctx.register(AppConfig.class, OtherConfig.class);
   ctx.register(AdditionalConfig.class);
   ctx.refresh();

   MyService myService = ctx.getBean(MyService.class);
   myService.doStuff();
}

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

由于使用基于 Java 的注释,因此还需要从 Java 安装目录添加 CGLIB.jar 和可从 asm.ow2.org 下载的 ASM.jar 库。

4

在 com.tutorialspoint 包下,创建 Java 类 HelloWorldConfig、HelloWorld 和 MainApp。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorldConfig.java 文件的内容

package com.tutorialspoint;
import org.springframework.context.annotation.*;

@Configuration
public class HelloWorldConfig {
   @Bean
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

以下是 HelloWorld.java 文件的内容

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

以下是 MainApp.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx =
         new AnnotationConfigApplicationContext(HelloWorldConfig.class);

      HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
      helloWorld.setMessage("Hello World!");
      helloWorld.getMessage();
   }
}

一旦完成创建所有源文件并添加了所需的附加库,即可运行应用程序。需要了解的是,不需要任何配置文件。如果一切正常,将在应用程序中打印以下消息 -

Your Message : Hello World!

Injecting Bean Dependencies

当 @Bean 彼此依赖时,表达依赖关系就像让一个 bean 方法调用另一个 bean 方法一样简单,如下所示 -

package com.tutorialspoint;
import org.springframework.context.annotation.*;

@Configuration
public class AppConfig {
   @Bean
   public Foo foo() {
      return new Foo(bar());
   }
   @Bean
   public Bar bar() {
      return new Bar();
   }
}

在此,foo bean 通过构造函数注入接收 bar 的引用。现在,考虑另一个工作示例。

Example

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

由于使用基于 Java 的注释,因此还需要从 Java 安装目录添加 CGLIB.jar 和可从 asm.ow2.org 下载的 ASM.jar 库。

4

在 com.tutorialspoint 包下,创建 Java 类 TextEditorConfig、TextEditor、SpellChecker 和 MainApp。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 TextEditorConfig.java 文件的内容

package com.tutorialspoint;
import org.springframework.context.annotation.*;

@Configuration
public class TextEditorConfig {
   @Bean
   public TextEditor textEditor(){
      return new TextEditor( spellChecker() );
   }

   @Bean
   public SpellChecker spellChecker(){
      return new SpellChecker( );
   }
}

以下是 TextEditor.java 文件的内容

package com.tutorialspoint;

public class TextEditor {
   private SpellChecker spellChecker;

   public TextEditor(SpellChecker spellChecker){
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck(){
      spellChecker.checkSpelling();
   }
}

以下是另一个依赖类文件 SpellChecker.java 的内容

package com.tutorialspoint;

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }
}

以下是 MainApp.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx =
         new AnnotationConfigApplicationContext(TextEditorConfig.class);

      TextEditor te = ctx.getBean(TextEditor.class);
      te.spellCheck();
   }
}

一旦完成创建所有源文件并添加了所需的附加库,即可运行应用程序。需要了解的是,不需要任何配置文件。如果一切正常,将在应用程序中打印以下消息 -

Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.

The @Import Annotation

@Import 注释允许从另一个配置类加载 @Bean 定义。考虑 ConfigA 类,如下所示 -

@Configuration
public class ConfigA {
   @Bean
   public A a() {
      return new A();
   }
}

可将上述 Bean 声明导入另一个 Bean 声明,如下所示 -

@Configuration
@Import(ConfigA.class)
public class ConfigB {
   @Bean
   public B b() {
      return new B();
   }
}

现在,与实例化上下文时需要指定 ConfigA.class 和 ConfigB.class 不同的是,只需要提供 ConfigB,如下所示 -

public static void main(String[] args) {
   ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);

   // now both beans A and B will be available...
   A a = ctx.getBean(A.class);
   B b = ctx.getBean(B.class);
}

Lifecycle Callbacks

@Bean 注释支持指定任意初始化和销毁回调方法,非常类似于 bean 元素上的 Spring XML 的 init-method 和 destroy-method 属性 -

public class Foo {
   public void init() {
      // initialization logic
   }
   public void cleanup() {
      // destruction logic
   }
}
@Configuration
public class AppConfig {
   @Bean(initMethod = "init", destroyMethod = "cleanup" )
   public Foo foo() {
      return new Foo();
   }
}

Specifying Bean Scope

默认范围是 singleton,但就像下面一样,可以用 @Scope 注释覆盖它 -

@Configuration
public class AppConfig {
   @Bean
   @Scope("prototype")
   public Foo foo() {
      return new Foo();
   }
}

Event Handling in Spring

您已在所有章节中了解到 Spring 的核心是 ApplicationContext ,它管理 bean 的完整生命周期。ApplicationContext 在加载 bean 时会发布特定类型的事件。例如,当上下文启动时,将发布 ContextStartedEvent,当上下文停止时,将发布 ContextStoppedEvent。

ApplicationContext 中的事件处理通过 ApplicationEvent 类和 ApplicationListener 接口来提供。因此,如果一个 bean 实现了 ApplicationListener,那么每次一个 ApplicationEvent 被发布到 ApplicationContext 时,该 bean 都会收到通知。

Spring 提供了以下标准事件 -

Sr.No.

Spring 内置事件和描述

1

ContextRefreshedEvent 此事件在 ApplicationContext 被初始化或刷新时发布。也可以使用 ConfigurableApplicationContext 接口上的 refresh() 方法触发此事件。

2

ContextStartedEvent 此事件在使用 ConfigurableApplicationContext 接口上的 start() 方法启动 ApplicationContext 时发布。您可以在收到此事件后轮询您的数据库或重新启动任何已停止的应用程序。

3

ContextStoppedEvent 此事件在使用 ConfigurableApplicationContext 接口上的 stop() 方法停止 ApplicationContext 时发布。您可以在收到此事件后执行所需的维护工作。

4

ContextClosedEvent 此事件在使用 ConfigurableApplicationContext 接口上的 close() 方法关闭 ApplicationContext 时发布。关闭的上下文已达到其生命周期结束;不能刷新或重新启动它。

5

RequestHandledEvent 这是一个特定于 Web 的事件,它告诉所有 bean 一个 HTTP 请求已经被服务。

Spring 的事件处理是单线程的,因此如果发布一个事件,直到所有接收者收到消息,进程才会被阻止,并且流程不会继续。因此,在设计需要使用事件处理的应用程序时应小心。

Listening to Context Events

为了监听上下文事件,bean 应实现 ApplicationListener 接口,该接口只有一个方法 onApplicationEvent() 。因此,让我们写一个示例来看一下事件如何传播,以及您如何将代码放在那里,以便根据某些事件执行所需的任务。

让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−

Step

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

在 com.tutorialspoint 包下创建 Java 类 HelloWorld、CStartEventHandler、CStopEventHandler 和 MainApp。

4

src 文件夹下创建 Beans 配置文件 Beans.xml。

5

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

以下是 CStartEventHandler.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;

public class CStartEventHandler
   implements ApplicationListener<ContextStartedEvent>{

   public void onApplicationEvent(ContextStartedEvent event) {
      System.out.println("ContextStartedEvent Received");
   }
}

以下是 CStopEventHandler.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;

public class CStopEventHandler
   implements ApplicationListener<ContextStoppedEvent>{

   public void onApplicationEvent(ContextStoppedEvent event) {
      System.out.println("ContextStoppedEvent Received");
   }
}

以下是 MainApp.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ConfigurableApplicationContext context =
         new ClassPathXmlApplicationContext("Beans.xml");

      // Let us raise a start event.
      context.start();

      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();

      // Let us raise a stop event.
      context.stop();
   }
}

以下是配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld">
      <property name = "message" value = "Hello World!"/>
   </bean>

   <bean id = "cStartEventHandler" class = "com.tutorialspoint.CStartEventHandler"/>
   <bean id = "cStopEventHandler" class = "com.tutorialspoint.CStopEventHandler"/>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

ContextStartedEvent Received
Your Message : Hello World!
ContextStoppedEvent Received

如果您愿意,您可以发布自己的自定义事件,稍后您可以获取这些事件并对它们执行任何操作。如果您有兴趣编写自己的自定义事件,可以检查 Custom Events in Spring.

Custom Events in Spring

编写和发布自定义事件需要进行很多步骤。遵循本章提供的指导编写、发布和处理 Custom Spring 事件。

Steps

Description

1

在创建的项目中使用名称 SpringExample 创建一个项目,并在 src 文件夹下创建一个包 com.tutorialspoint 。所有类都将在此包下创建。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

通过扩展 ApplicationEvent 创建一个事件类 CustomEvent。此类必须定义一个默认构造函数,该函数应从 ApplicationEvent 类继承构造函数。

4

一旦定义了事件类,便可以从任何类(例如,实现了 ApplicationEventPublisherAware 的 EventClassPublisher)发布该事件。还需要在 XML 配置文件中将此类声明为 bean,以便容器可以将该 bean 识别为事件发布者,因为它实现了 ApplicationEventPublisherAware 接口。

5

可以再一个类中(例如,实现了 ApplicationListener 接口,并为自定义事件实现了 onApplicationEvent 方法的 EventClassHandler)处理已发布的事件。

6

src 文件夹下创建 bean 配置文件 Beans.xml,以及一个作为 Spring 应用程序运行的 MainApp 类。

7

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

下面是 CustomEvent.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent{
   public CustomEvent(Object source) {
      super(source);
   }
   public String toString(){
      return "My Custom Event";
   }
}

下面是 CustomEventPublisher.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

public class CustomEventPublisher implements ApplicationEventPublisherAware {
   private ApplicationEventPublisher publisher;

   public void setApplicationEventPublisher (ApplicationEventPublisher publisher) {
      this.publisher = publisher;
   }
   public void publish() {
      CustomEvent ce = new CustomEvent(this);
      publisher.publishEvent(ce);
   }
}

下面是 CustomEventHandler.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ApplicationListener;

public class CustomEventHandler implements ApplicationListener<CustomEvent> {
   public void onApplicationEvent(CustomEvent event) {
      System.out.println(event.toString());
   }
}

以下是 MainApp.java 文件的内容

package com.tutorialspoint;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ConfigurableApplicationContext context =
         new ClassPathXmlApplicationContext("Beans.xml");

      CustomEventPublisher cvp =
         (CustomEventPublisher) context.getBean("customEventPublisher");

      cvp.publish();
      cvp.publish();
   }
}

以下是配置文件 Beans.xml

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "customEventHandler" class = "com.tutorialspoint.CustomEventHandler"/>
   <bean id = "customEventPublisher" class = "com.tutorialspoint.CustomEventPublisher"/>

</beans>

完成源文件和 Bean 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−

y Custom Event
y Custom Event

AOP with Spring Framework

Spring Framework 的关键组件之一是 Aspect oriented programming (AOP) 框架。面向方面编程将程序逻辑细分为称为关注点的不同部分。跨越应用程序多个点的函数称为 cross-cutting concerns ,这些跨领域关注点在概念上与应用程序的业务逻辑分离。记录、审核、声明式事务、安全、缓存等方面有很多常见的例子。

面向对象编程中模块化的关键单元是类,而在面向方面编程中,模块化的单元是方面。依赖注入可帮助你解除应用程序对象之间的耦合,面向方面编程可帮助你解除跨领域关注点与它们所影响的对象之间的耦合。面向方面编程类似于 Perl、.NET、Java 和其他编程语言中的触发器。

Spring AOP 模块提供拦截器来拦截应用程序。例如,当执行方法时,你可以在方法执行之前或之后添加额外功能。

AOP Terminologies

在我们开始使用面向方面编程之前,让我们熟悉面向方面编程的概念和术语。这些术语并非特定于 Spring,而是与面向方面编程相关。

Sr.No

Terms & Description

1

Aspect 此模块有一组 API,提供跨领域要求。例如,日志记录模块将被称为用于日志记录的面向方面编程方面。应用程序可以具有任意数量的方面,取决于要求。

2

Join point 此模块表示应用程序中的某个点,你可以在这里插入面向方面编程方面。也可以说,这是应用程序中使用 Spring 面向方面编程框架执行操作的实际位置。

3

Advice 这是在方法执行之前或之后要采取的实际操作。这是 Spring 面向方面编程框架在程序执行期间调用的实际代码段。

4

Pointcut 这是一组一个或多个联接点,应在其中执行通知。你可以使用表达式或模式指定切入点,如我们在面向方面编程示例中所看到的。

5

Introduction 引入允许你向现有类添加新方法或属性。

6

Target object 由一个或多个方面告知的对象。此对象将始终是一个代理对象,也称为告知对象。

7

Weaving 编织是将方面与其他应用程序类型或对象链接以创建告知对象的过程。此操作可以在编译时、加载时或运行时完成。

Types of Advice

@Spring 方面可使用如下所述的五种建议进行处理:

Sr.No

Advice & Description

1

before 在方法执行前运行建议。

2

after 在方法执行后运行建议,无论其执行结果为何。

3

after-returning 仅在方法成功完成时,才在方法执行后运行建议。

4

after-throwing 仅在方法通过抛出异常而退出时,才在方法执行后运行建议。

5

around 在调用建议方法之前和之后运行建议。

Custom Aspects Implementation

Spring 支持 @AspectJ annotation style 方法和 schema-based 方法来实现自定义方面。这两个方法在以下部分中已作了详细说明。

Sr.No

Approach & Description

1

XML Schema based 方面使用常规类和基于 XML 的配置来实现。

2

@AspectJ based @AspectJ 指代一种将方面声明为常规 Java 类的样式,对其使用 Java 5 注释进行注释。

Spring - JDBC Framework Overview

在处理普通老 JDBC 使用数据库时,编写不必要的代码来处理异常、打开和关闭数据库连接会变得繁琐等。然而,Spring JDBC 框架会处理所有低级别详细信息,从打开连接开始,准备并执行 SQL 语句,处理异常,处理事务,最后关闭连接。

因此,您所要做的就是定义连接参数并指定要执行的 SQL 语句,并在从数据库获取数据时对每次迭代执行所需的工作。

Spring JDBC 提供了多种方法和相应的不同类来与数据库进行交互。我将采用的方法是经典的、最流行的方法,它使用框架的 JdbcTemplate 类。这是管理所有数据库通信和异常处理的中央框架类。

JdbcTemplate Class

JDBC Template 类执行 SQL 查询、更新语句、存储过程调用、对 ResultSets 执行迭代并提取返回的参数值。它还会捕获 JDBC 异常,并将它们转换到在 org.springframework.dao 包中定义的通用、更具信息性的异常层次结构。

一旦配置,JdbcTemplate 类的实例就是线程安全的。因此,您可以配置 JdbcTemplate 的一个实例,然后将此共享引用安全地注入至多个 DAO。

在使用 JDBC Template 类时的一个常见做法是在您的 Spring 配置文件中配置一个 DataSource,然后将共享 DataSource bean 依赖注入到 DAO 类中,并且在 DataSource 的 setter 中创建 JdbcTemplate。

Configuring Data Source

让我们在我们的数据库 TEST 中创建一个数据库表 Student 。我们假设您使用的是 MySQL 数据库,如果您使用的是任何其他数据库,则可相应地更改您的 DDL 和 SQL 查询。

CREATE TABLE Student(
   ID   INT NOT NULL AUTO_INCREMENT,
   NAME VARCHAR(20) NOT NULL,
   AGE  INT NOT NULL,
   PRIMARY KEY (ID)
);

现在,我们需要向 JDBC Template 提供一个 DataSource,以便它可以自行配置以获取数据库访问权。您可以在 XML 文件中配置 DataSource,其代码如下图所示代码片段所示:

<bean id = "dataSource"
   class = "org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name = "driverClassName" value = "com.mysql.jdbc.Driver"/>
   <property name = "url" value = "jdbc:mysql://localhost:3306/TEST"/>
   <property name = "username" value = "root"/>
   <property name = "password" value = "password"/>
</bean>

Data Access Object (DAO)

DAO 表示数据访问对象,通常用于数据库交互。DAO 存在于提供读取和向数据库写入数据的方法,并且它们应通过一个接口暴露出此功能,应用程序的其余部分将通过此接口访问它们。

Spring 中的 DAO 支持可以轻松以一致方式使用像 JDBC、Hibernate、JPA 或 JDO 这样的数据访问技术。

Executing SQL statements

让我们了解如何使用 SQL 和 JDBC 模板对象对数据库表执行 CRUD(创建、读取、更新和删除)操作。

Querying for an integer

String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );

Querying for a long

String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );

A simple query using a bind variable

String SQL = "select age from Student where id = ?";
int age = jdbcTemplateObject.queryForInt(SQL, new Object[]{10});

Querying for a String

String SQL = "select name from Student where id = ?";
String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);

Querying and returning an object

String SQL = "select * from Student where id = ?";
Student student = jdbcTemplateObject.queryForObject(
   SQL, new Object[]{10}, new StudentMapper());

public class StudentMapper implements RowMapper<Student> {
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setID(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));

      return student;
   }
}

Querying and returning multiple objects

String SQL = "select * from Student";
List<Student> students = jdbcTemplateObject.query(
   SQL, new StudentMapper());

public class StudentMapper implements RowMapper<Student> {
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setID(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));

      return student;
   }
}

Inserting a row into the table

String SQL = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );

Updating a row into the table

String SQL = "update Student set name = ? where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );

Deleting a row from the table

String SQL = "delete Student where id = ?";
jdbcTemplateObject.update( SQL, new Object[]{20} );

Executing DDL Statements

你可以使用 jdbcTemplate 的 execute(..) 方法来执行任何 SQL 语句或 DDL 语句。以下是使用 CREATE 语句创建表的示例:

String SQL = "CREATE TABLE Student( " +
   "ID   INT NOT NULL AUTO_INCREMENT, " +
   "NAME VARCHAR(20) NOT NULL, " +
   "AGE  INT NOT NULL, " +
   "PRIMARY KEY (ID));"

jdbcTemplateObject.execute( SQL );

Spring JDBC Framework Examples

基于以上概念,让我们查看几个重要的示例,将帮助你理解 Spring 中 JDBC 框架的用法:

Sr.No.

Example & Description

1

Spring JDBC Example 此示例将说明如何编写一个简单的基于 JDBC 的 Spring 应用程序。

2

SQL Stored Procedure in Spring 了解如何在 Spring 中使用 JDBC 调用 SQL 存储过程。

Spring - Transaction Management

数据库事务是一系列操作,它们被当作一个工作单元执行。这些操作应要么全部完成,要么完全不产生任何效果。事务管理是面向 RDBMS 的企业应用程序的重要组成部分,以确保数据完整性和一致性。事务的概念可以用以下四项关键特性来描述 ACID

  1. Atomicity − 事务应作为一个操作单元来处理,这意味着操作序列要么全部成功,要么全部失败。

  2. Consistency − 这表示了数据库的引用完整性一致性、表中的唯一主键等。

  3. Isolation − 可能有多个事务同时处理相同的数据集。应将每个事务隔离起来以防止数据损坏。

  4. Durability − 一旦事务完成,该事务的结果必须变为永久性并且不能因系统故障而被删除。

真正的 RDBMS 数据库系统将为每个事务保证所有四个特性。使用 SQL 向数据库发出的事务的简单视图如下 −

  1. 使用开始事务命令开始事务。

  2. 使用 SQL 查询执行各种删除、更新或插入操作。

  3. 如果所有操作都成功,则执行提交,否则回滚所有操作。

Spring 框架在不同基础事务管理 API 的基础上提供了抽象层。Spring 的事务支持旨在通过向 POJO 添加事务功能来提供 EJB 事务的替代方案。Spring支持基于编程和声明的事务管理。EJB 需要应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现。

Local vs. Global Transactions

本地事务特定于单个事务性资源(例如 JDBC 连接),而全局事务则可以跨越多个事务性资源(例如分布式系统中的事务)。

当应用程序组件和资源位于一个站点时,本地事务管理在集中计算环境中可能很有用,并且事务管理仅涉及在单台机器上运行的本地数据管理器。本地事务更容易实现。

在所有资源都分布在多个系统中的分布式计算环境中需要全局事务管理。在这种情况下,需要在本地和全局级别执行事务管理。跨多个系统执行分布式或全局事务,并且其执行要求全局事务管理系统和所有相关系统的所有本地数据管理程序之间的协调。

Programmatic vs. Declarative

Spring支持两种类型的事务管理−

  1. Programmatic transaction management − 这意味着您必须借助编程来管理事务。这样会赋予您极大的灵活性,但难以维护。

  2. Declarative transaction management − 这意味着您将事务管理与业务代码分开。您只使用批注或基于 XML 的配置来管理事务。

声明性事务管理优于编程事务管理,尽管它不如编程事务管理灵活,而后者允许您通过代码控制事务。但作为一种横切关注点,声明性事务管理可以通过 AOP 方法模块化。Spring 通过 Spring AOP 框架支持声明性事务管理。

Spring Transaction Abstractions

Spring 事务抽象的关键由 org.springframework.transaction.PlatformTransactionManager 接口定义,如下所示 −

public interface PlatformTransactionManager {
   TransactionStatus getTransaction(TransactionDefinition definition);
   throws TransactionException;

   void commit(TransactionStatus status) throws TransactionException;
   void rollback(TransactionStatus status) throws TransactionException;
}

Sr.No

Method & Description

1

TransactionStatus getTransaction(TransactionDefinition definition) 此方法根据指定传播行为,返回当前活动事务或创建一个新事务。

2

void commit(TransactionStatus status) 此方法提交给定事务,并考虑其状态。

3

void rollback(TransactionStatus status) 此方法对给定事务执行回滚。

TransactionDefinition 是 Spring 中事务支持的核心接口,定义如下 −

public interface TransactionDefinition {
   int getPropagationBehavior();
   int getIsolationLevel();
   String getName();
   int getTimeout();
   boolean isReadOnly();
}

Sr.No

Method & Description

1

int getPropagationBehavior() 此方法返回传播行为。Spring 提供了所有 EJB CMT 中熟悉的事务传播选项。

2

int getIsolationLevel() 此方法返回事务与其他事务的工作隔绝程度。

3

String getName() 此方法返回事务的名称。

4

int getTimeout() 此方法以秒为单位返回事务必须完成的时间。

5

boolean isReadOnly() 此方法返回事务是否为只读。

以下是隔离级别的可能值 −

Sr.No

Isolation & Description

1

TransactionDefinition.ISOLATION_DEFAULT 这是默认隔离级别。

2

TransactionDefinition.ISOLATION_READ_COMMITTED 表示会阻止脏读;可能发生不可重复读和幻读。

3

TransactionDefinition.ISOLATION_READ_UNCOMMITTED 表示可能发生脏读、不可重复读和幻读。

4

TransactionDefinition.ISOLATION_REPEATABLE_READ 表示会阻止脏读和不可重复读;可能发生幻读。

5

TransactionDefinition.ISOLATION_SERIALIZABLE 表示会阻止脏读、不可重复读和幻读。

以下是传播类型的可能值 −

Sr.No.

Propagation & Description

1

TransactionDefinition.PROPAGATION_MANDATORY 支持当前事务;如果不存在当前事务,则会引发异常。

2

*TransactionDefinition.PROPAGATION_NESTED *如果存在当前事务,则在嵌套事务中执行。

3

*TransactionDefinition.PROPAGATION_NEVER *不支持当前事务;如果存在当前事务,则会引发异常。

4

*事务定义.PROPAGATION_NOT_SUPPORTED*不支持当前事务;相反,始终非事务性地执行。

5

TransactionDefinition.PROPAGATION_REQUIRED 支持当前事务;如果不存在事务,则创建一个新事务。

6

TransactionDefinition.PROPAGATION_REQUIRES_NEW 创建一个新事务,如果存在当前事务,则暂停该事务。

7

TransactionDefinition.PROPAGATION_SUPPORTS 支持当前事务;如果不存在事务,则非事务性地执行。

8

TransactionDefinition.TIMEOUT_DEFAULT 使用基础事务系统的默认超时,如果没有支持超时,则不使用。

事务状态接口为事务代码提供了一种简单的方法来控制事务执行和查询事务状态。

public interface TransactionStatus extends SavepointManager {
   boolean isNewTransaction();
   boolean hasSavepoint();
   void setRollbackOnly();
   boolean isRollbackOnly();
   boolean isCompleted();
}

Sr.No.

Method & Description

1

boolean hasSavepoint() 此方法返回此事务是否在内部携带保存点,即是否已基于保存点创建为嵌套事务。

2

boolean isCompleted() 此方法返回此事务是否已完成,即是否已提交或回滚。

3

boolean isNewTransaction() 如果当前事务是新的,则此方法返回 true。

4

boolean isRollbackOnly() 此方法返回事务是否已标记为仅回滚。

5

void setRollbackOnly() 此方法将事务设置为仅回滚。

Spring - MVC Framework

Spring Web MVC 框架提供了模型-视图-控制器 (MVC) 架构和可用作开发灵活且松散耦合的 Web 应用程序的现成组件。MVC 模式导致应用程序的不同方面(输入逻辑、业务逻辑和 UI 逻辑)分离,同时在这些元素中提供松散耦合。

  1. Model 封装了应用程序数据,并且通常将由 POJO 组成。

  2. View 负责呈现模型数据,并且通常生成客户端浏览器可以解释的 HTML 输出。

  3. Controller 负责处理用户请求、构建适当的模型并将其传递给视图进行呈现。

The DispatcherServlet

Spring Web 模型-视图-控制器(MVC)框架围绕着处理所有 HTTP 请求和响应的 DispatcherServlet 而设计。Spring Web MVC DispatcherServlet 的请求处理工作流在以下图表中说明:

spring dispatcherservlet

以下为响应发送到 DispatcherServlet 的入站 HTTP 请求的事件序列 -

  1. 收到 HTTP 请求后,DispatcherServlet 咨询 HandlerMapping 以调用合适的 Controller。

  2. Controller 接收该请求并基于使用的 GET 或 POST 方法调用合适的服务方法。服务方法会基于定义的业务逻辑来设置模型数据,并将视图名称返回给 DispatcherServlet。

  3. DispatcherServlet 将使用 ViewResolver 的帮助来为该请求挑选定义的视图。

  4. 一旦视图确定,DispatcherServlet 将把模型数据传递给该视图,该视图最终在浏览器中呈现。

所有上述组件(即 HandlerMapping、Controller 和 ViewResolver)都是 WebApplicationContext 的一部分,WebApplicationContext 是带有额外功能的 plainApplicationContext 的扩展(这些功能对于 Web 应用程序而言非常有必要)。

Required Configuration

您需要使用 web.xml 文件中的 URL 映射来映射您希望 DispatcherServlet 处理的请求。以下示例展示了 HelloWeb DispatcherServlet 的声明和映射 -

<web-app id = "WebApp_ID" version = "2.4"
   xmlns = "http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   <display-name>Spring MVC Application</display-name>

   <servlet>
      <servlet-name>HelloWeb</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
      <servlet-name>HelloWeb</servlet-name>
      <url-pattern>*.jsp</url-pattern>
   </servlet-mapping>

</web-app>

web.xml 文件将保存在您的 Web 应用程序的 WebContent/WEB-INF 目录中。在初始化 HelloWeb DispatcherServlet 时,框架将尝试从位于该应用程序的 WebContent/WEB-INF 目录中的名为 [servlet-name]-servlet.xml 的文件中加载应用程序上下文。在本案例中,我们的文件将是 HelloWebservlet.xml

接下来,<servlet-mapping> 标记表明哪些 URL 将由哪个 DispatcherServlet 处理。这里,所有以 .jsp 结尾的 HTTP 请求都将由 HelloWeb DispatcherServlet 处理。

如果您不想使用 [servlet-name]-servlet.xml 作为默认文件名,也不想使用 WebContent/WEB-INF 作为默认位置,您可以通过在 web.xml 文件中添加 ContextLoaderListener servlet 监听器来自定义该文件名和位置,如下所示: -

<web-app...>

   <!-------- DispatcherServlet definition goes here----->
   ....
   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/HelloWeb-servlet.xml</param-value>
   </context-param>

   <listener>
      <listener-class>
         org.springframework.web.context.ContextLoaderListener
      </listener-class>
   </listener>

</web-app>

现在,让我们检查位于您的 Web 应用程序的 WebContent/WEB-INF 目录中的 HelloWeb-servlet.xml 文件所需的配置: -

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:context = "http://www.springframework.org/schema/context"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package = "com.tutorialspoint" />

   <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name = "prefix" value = "/WEB-INF/jsp/" />
      <property name = "suffix" value = ".jsp" />
   </bean>

</beans>

以下为 HelloWeb-servlet.xml 文件的重要之处 -

  1. [servlet-name]-servlet.xml 文件将用于创建已定义的 Bean,覆盖全局范围内使用相同名称定义的任何 Bean 的定义。

  2. <context:component-scan…​> 标记将用于激活 Spring MVC 注解扫描能力,该能力允许使用诸如 @Controller 和 @RequestMapping 等注解。

  3. InternalResourceViewResolver 将具有用于解析视图名称的规则。根据上述定义的规则,逻辑视图 hello 委托给了位于 /WEB-INF/jsp/hello.jsp 的某个视图实现。

以下部分将向您展示如何创建您的实际组件,即 Controller、Model 和 View。

Defining a Controller

DispatcherServlet 将请求委托给 controller 以执行特定于该请求的功能。 @Controller 注解表明特定的类扮演 controller 的角色。 @RequestMapping 注解用于将 URL 映射到整个类或特定的处理方法。

@Controller
@RequestMapping("/hello")
public class HelloController {
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

@Controller 注解将类定义为 Spring MVC controller。这里,首次使用 @RequestMapping 表明此 controller 上的所有处理方法都相对于 /hello 路径。接下来,注解 @RequestMapping(method = RequestMethod.GET) 用于将 printHello() 方法声明为 controller 处理 HTTP GET 请求的默认服务方法。您可以在相同的 URL 定义另一个方法来处理任何 POST 请求。

您可以用另一种形式来编写上述 controller,其中可以在 @RequestMapping 中添加附加的属性,如下所示: -

@Controller
public class HelloController {
   @RequestMapping(value = "/hello", method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

value 属性表示处理程序方法映射到的网址, method 属性定义了处理 HTTP GET 请求的服务方法。下面是关于上面定义的控制器的几个要点:

  1. 您将在一个服务方法中定义所需的业务逻辑。您可以在此方法中根据要求调用其他方法。

  2. 基于所定义的业务逻辑,您将在这个方法中创建一个模型。您可以使用 setter 来设置不同的模型属性,视图将访问这些属性以展示最终结果。此示例创建一个具有属性“message”的模型。

  3. 定义的服务方法可以返回一个 String,它包含用于渲染模型的 view 的名称。此示例返回“hello”作为逻辑视图名称。

Creating JSP Views

Spring MVC 支持许多类型的视图以用于不同的表示技术。其中包括有:JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 源、JasperReports 等。但是,我们最常使用带有 JSTL 的 JSP 模板。

让我们在 /WEB-INF/hello/hello.jsp 中编写一个简单的 hello 视图:

<html>
   <head>
      <title>Hello Spring MVC</title>
   </head>

   <body>
      <h2>${message}</h2>
   </body>
</html>

此处 ${message} 是我们在控制器中设置的属性。您可以在您的视图中显示多个属性。

Spring Web MVC Framework Examples

基于上述概念,让我们查看几个重要的示例,它们将帮助您构建您的 Spring Web 应用程序:

Sr.No.

Example & Description

1

Spring MVC Hello World Example 此示例将阐述如何编写一个简单的 Spring Web Hello World 应用程序。

2

Spring MVC Form Handling Example 此示例将阐述如何使用 HTML 表单将数据提交到控制器,并显示处理过的结果来编写 Spring Web 应用程序。

3

Spring Page Redirection Example 了解如何在 Spring MVC Framework 中使用页面重定向功能。

4

Spring Static Pages Example 了解如何在 Spring MVC Framework 中访问静态页面以及动态页面。

5

Spring Exception Handling Example 了解如何在 Spring MVC Framework 中处理异常。

Spring - Logging with Log4J

这是一个非常易于使用的 Spring 应用程序中的 Log4J 功能。以下示例将引导你完成一些简单的步骤,以解释 Log4J 和 Spring 之间的简单集成。

我们假设你已在机器上安装了 log4J 。如果没有,则可以从 https://logging.apache.org/ 下载它,然后只需将压缩文件解压到任意文件夹中。我们只会在我们的项目中使用 log4j-x.y.z.jar

接下来,让我们准备一个运行中的 Eclipse IDE,并按照以下步骤使用 Spring Web 框架开发基于动态表单的 Web 应用程序:

Steps

Description

1

使用 SpringExample 创建一个项目,并在创建的项目 src 文件夹下创建 com.tutorialspoint 包。

2

使用 Add External JARs 选项添加必需的 Spring 库,如 Spring Hello World Example 章节中所述。

3

同样使用 Add External JARs 在项目中添加 log4j 库 log4j-x.y.z.jar。

4

在 com.tutorialspoint 包下创建 Java 类 HelloWorld 和 MainApp。

5

src 文件夹下创建 Beans 配置文件 Beans.xml。

6

src 文件夹下创建 log4J 配置文件 log4j.properties。

7

最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按如下所述运行应用程序。

以下是 HelloWorld.java 文件的内容

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage() {
      System.out.println("Your Message : " + message);
   }
}

以下是第二个文件的内容 MainApp.java

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.log4j.Logger;

public class MainApp {
   static Logger log = Logger.getLogger(MainApp.class.getName());

   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      log.info("Going to create HelloWord Obj");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();

      log.info("Exiting the program");
   }
}

您可以像生成信息消息一样生成 debugerror 信息。现在让我们看看 Beans.xml 文件的内容

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld">
      <property name = "message" value = "Hello World!"/>
   </bean>

</beans>

以下是 log4j.properties 的内容,它定义了 Log4J 生成日志消息所需的标准规则

# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE

# Define the file appender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=C:\\log.out

# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true

# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug

# Set the append to false, overwrite
log4j.appender.FILE.Append=false

# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

在您创建源文件和 bean 配置文件后,让我们运行应用程序。如果您的应用程序一切正常,它将在 Eclipse 控制台中打印以下消息:

Your Message : Hello World!

如果您检查 C:\\ 驱动器,那么您应该会发现日志文件 log.out ,其中包含各个日志消息,如下所示:

<!-- initialization log messages -->

Going to create HelloWord Obj
Returning cached instance of singleton bean 'helloWorld'
Exiting the program

Jakarta Commons Logging (JCL) API

或者,您可以使用 Jakarta Commons Logging (JCL) API 在 Spring 应用程序中生成日志。可以从 https://jakarta.apache.org/commons/logging/ 下载 JCL。在该软件包之外,我们唯一在技术上需要的就是 commons-logging-x.y.z.jar 文件,该文件需要以与在上述示例中放置 log4j-x.y.z.jar 相同的方式置于您的类路径中。

要使用日志记录功能,您需要 org.apache.commons.logging.Log 对象,然后您可以根据需求调用以下方法之一:

  1. fatal(Object message)

  2. error(Object message)

  3. warn(Object message)

  4. info(Object message)

  5. debug(Object message)

  6. trace(Object message)

以下是 MainApp.java 的替换内容,它使用 JCL API

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.commons.logging. Log;
import org.apache.commons.logging. LogFactory;

public class MainApp {
   static Log log = LogFactory.getLog(MainApp.class.getName());

   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      log.info("Going to create HelloWord Obj");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();

      log.info("Exiting the program");
   }
}

您必须确保在编译和运行程序之前已将 commons-logging-x.y.z.jar 文件包含在您的项目中。

现在,在上述示例中保持其余的配置和内容不变,如果您编译并运行应用程序,您将获得与使用 Log4J API 相似的结果。