- Spring 核心基础知识
- 春天 - 主页
- 春天 - 概述
- 春天-建筑
- Spring - 环境设置
- Spring - Hello World 示例
- Spring - IoC 容器
- Spring - Bean 定义
- Spring - Bean 范围
- Spring - Bean 生命周期
- Spring - Bean 后处理器
- Spring-Bean定义继承
- Spring - 依赖注入
- Spring - 注入内部 Bean
- Spring - 注入集合
- Spring - Bean 自动装配
- 基于注释的配置
- Spring - 基于Java的配置
- Spring - Spring 中的事件处理
- Spring - Spring 中的自定义事件
- Spring - 使用 Spring 框架的 AOP
- Spring - JDBC 框架
- Spring-事务管理
- Spring - Web MVC 框架
- Spring - 使用 Log4J 进行日志记录
- 春季问答
- 春天 - 问题与解答
- 春季有用资源
- 春天 - 快速指南
- Spring - 有用的资源
- 春天 - 讨论
春天 - 快速指南
Spring 框架 - 概述
Spring 是最流行的企业 Java 应用程序开发框架。全球数以百万计的开发人员使用 Spring 框架来创建高性能、易于测试和可重用的代码。
Spring框架是一个开源的Java平台。它最初由 Rod Johnson 编写,并于 2003 年 6 月首次在 Apache 2.0 许可证下发布。
Spring 在尺寸和透明度方面是轻量级的。Spring框架的基础版大小在2MB左右。
Spring 框架的核心功能可用于开发任何 Java 应用程序,但也有用于在 Java EE 平台上构建 Web 应用程序的扩展。Spring 框架的目标是使 J2EE 开发更易于使用,并通过启用基于 POJO 的编程模型来促进良好的编程实践。
使用 Spring 框架的好处
以下是使用 Spring 框架的一些巨大好处的列表 -
Spring 使开发人员能够使用 POJO 开发企业级应用程序。仅使用 POJO 的好处是您不需要 EJB 容器产品(例如应用程序服务器),但您可以选择仅使用强大的 servlet 容器(例如 Tomcat 或某些商业产品)。
Spring 以模块化方式组织。尽管包和类的数量很大,但您只需担心您需要的包和类,而忽略其余的。
Spring 并没有重新发明轮子,而是真正利用了一些现有的技术,例如一些 ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器以及其他视图技术。
测试用 Spring 编写的应用程序很简单,因为依赖于环境的代码已移至该框架中。此外,通过使用 JavaBeanstyle POJO,使用依赖注入来注入测试数据变得更加容易。
Spring 的 Web 框架是一个设计良好的 Web MVC 框架,它为 Struts 等 Web 框架或其他过度设计或不太流行的 Web 框架提供了一个很好的替代方案。
Spring 提供了一个方便的 API,用于将特定于技术的异常(例如,由 JDBC、Hibernate 或 JDO 引发的异常)转换为一致的、未经检查的异常。
轻量级 IoC 容器往往是轻量级的,尤其是与 EJB 容器相比。这有利于在内存和CPU资源有限的计算机上开发和部署应用程序。
Spring 提供了一致的事务管理接口,可以缩小到本地事务(例如使用单个数据库)并扩展到全局事务(例如使用 JTA)。
依赖注入(DI)
Spring 最受认可的技术是控制反转的依赖注入 (DI)风格。控制反转(IoC)是一个通用概念,可以用多种不同的方式表达。依赖注入只是控制反转的一个具体示例。
在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类并在单元测试时独立于其他类进行测试的可能性。依赖注入有助于将这些类粘合在一起,同时保持它们的独立性。
到底什么是依赖注入?我们分别来看这两个词。这里的依赖部分转化为两个类之间的关联。例如,A类依赖于B类。现在,我们看第二部分,注入。所有这些意味着,B 类将由 IoC 注入到 A 类中。
依赖注入可以通过将参数传递给构造函数或使用 setter 方法进行后构造的方式发生。由于依赖注入是 Spring 框架的核心,我们将在单独的章节中通过相关示例来解释这个概念。
面向方面编程(AOP)
Spring 的关键组件之一是面向方面编程(AOP)框架。跨越应用程序多个点的功能称为横切关注点,这些横切关注点在概念上与应用程序的业务逻辑是分开的。方面有各种常见的好例子,包括日志记录、声明性事务、安全性、缓存等。
OOP 中模块化的关键单元是类,而 AOP 中模块化的单元是方面。DI 帮助您将应用程序对象彼此解耦,而 AOP 帮助您将横切关注点与其影响的对象解耦。
Spring框架的AOP模块提供了面向方面的编程实现,允许您定义方法拦截器和切入点,以干净地解耦实现应该分离的功能的代码。我们将在单独的章节中讨论更多有关 Spring AOP 概念的内容。
Spring 框架 - 架构
Spring 可能成为所有企业应用程序的一站式商店。然而,Spring 是模块化的,允许您挑选适合您的模块,而无需引入其余的模块。以下部分提供了有关 Spring 框架中所有可用模块的详细信息。
Spring框架提供了大约20个模块,可以根据应用程序的需求来使用。
核心容器
核心容器由核心、Bean、上下文和表达式语言模块组成,其详细信息如下:
核心模块提供了框架的基本部分,包括 IoC 和依赖注入功能。
Bean模块提供了 BeanFactory,它是工厂模式的复杂实现。
Context模块构建在 Core 和 Beans 模块提供的坚实基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext 接口是Context 模块的焦点。
SpEL模块提供了强大的表达式语言,用于在运行时查询和操作对象图。
数据访问/集成
数据访问/集成层由 JDBC、ORM、OXM、JMS 和事务模块组成,其详细信息如下:
JDBC模块提供了一个 JDBC 抽象层,消除了繁琐的 JDBC 相关编码的需要。
ORM模块为流行的对象关系映射 API 提供集成层,包括 JPA、JDO、Hibernate 和 iBatis。
OXM模块提供了一个抽象层,支持 JAXB、Castor、XMLBeans、JiBX 和 XStream 的对象/XML 映射实现。
Java 消息传递服务JMS模块包含用于生成和使用消息的功能。
Transaction模块支持实现特殊接口的类和所有 POJO 的编程式和声明式事务管理。
网络
Web层由Web、Web-MVC、Web-Socket和Web-Portlet模块组成,其详细信息如下:
Web模块提供基本的面向 Web 的集成功能,例如分段文件上传功能以及使用 servlet 侦听器和面向 Web 的应用程序上下文初始化 IoC 容器。
Web -MVC模块包含 Spring 的 Web 应用程序的模型-视图-控制器 (MVC) 实现。
Web -Socket模块为 Web 应用程序中客户端和服务器之间基于 WebSocket 的双向通信提供支持。
Web -Portlet模块提供在 Portlet 环境中使用的 MVC 实现,并镜像 Web-Servlet 模块的功能。
各种各样的
还有一些其他重要的模块,如 AOP、Aspects、Instrumentation、Web 和 Test 模块,其详细信息如下:
AOP模块提供了面向方面的编程实现,允许您定义方法拦截器和切入点,以干净地解耦实现应分离的功能的代码。
Aspects模块提供与 AspectJ 的集成,AspectJ 又是一个强大且成熟的 AOP 框架。
Instrumentation模块提供类检测支持和类加载器实现,以在某些应用程序服务器中使用。
消息传递模块提供对 STOMP 作为 WebSocket 子协议在应用程序中使用的支持。它还支持注释编程模型,用于路由和处理来自 WebSocket 客户端的 STOMP 消息。
Test模块支持使用 JUnit或TestNG 框架测试 Spring 组件。
Spring - 环境设置
本章将指导您如何准备开发环境以开始使用 Spring 框架。它还将教您如何在设置 Spring 框架之前在计算机上设置 JDK、Tomcat 和 Eclipse -
第 1 步 - 设置 Java 开发工具包 (JDK)
您可以从 Oracle 的 Java 站点 - Java SE 下载下载最新版本的 SDK 。您将在下载的文件中找到安装 JDK 的说明,按照给定的说明进行安装和配置设置。最后设置 PATH 和 JAVA_HOME 环境变量以引用包含 java 和 javac 的目录,通常分别为 java_install_dir/bin 和 java_install_dir。
如果您运行的是 Windows 并已将 JDK 安装在 C:\jdk1.6.0_15 中,则必须将以下行放入 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
或者,如果您使用集成开发环境 (IDE),如 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio,则必须编译并运行一个简单的程序来确认 IDE 知道您安装了 Java 的位置。否则,您将必须按照 IDE 文档中的规定进行正确的设置。
第 2 步 - 安装 Apache 通用日志记录 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文件以及其他支持文档等。
确保在此目录中正确设置 CLASSPATH 变量,否则在运行应用程序时将遇到问题。
第 3 步 - 设置 Eclipse IDE
本教程中的所有示例都是使用 Eclipse IDE 编写的。因此,我们建议您应该在计算机上安装最新版本的 Eclipse。
要安装 Eclipse IDE,请从https://www.eclipse.org/downloads/下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压到一个方便的位置。例如,在 Windows 上的 C:\eclipse 中,或在 Linux/Unix 上的 /usr/local/eclipse 中,最后适当地设置 PATH 变量。
Eclipse 可以通过在 Windows 机器上执行以下命令来启动,或者只需双击 eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令来启动 Eclipse -
$/usr/local/eclipse/eclipse
成功启动后,如果一切正常,那么它应该显示以下结果 -
第 4 步 - 设置 Spring 框架库
现在,如果一切正常,那么您可以继续设置 Spring 框架。以下是在您的计算机上下载并安装框架的简单步骤。
选择要在 Windows 还是 Unix 上安装 Spring,然后继续下一步,下载适用于 Windows 的 .zip 文件和适用于 Unix 的 .tz 文件。
从https://repo.spring.io/release/org/springframework/spring下载最新版本的 Spring 框架二进制文件。
在开发本教程时,spring-framework-4.1.6.RELEASE-dist.zip已下载到 Windows 计算机上。下载的文件解压后,在E:\spring中给出如下目录结构。
您将在目录E:\spring\libs中找到所有 Spring 库。确保在此目录中正确设置 CLASSPATH 变量,否则在运行应用程序时将遇到问题。如果您使用Eclipse,则不需要设置CLASSPATH,因为所有设置都将通过Eclipse完成。
完成最后一步后,您就可以开始下一章中的第一个 Spring 示例了。
Spring - Hello World 示例
让我们开始使用 Spring 框架进行实际编程。在开始使用 Spring 框架编写第一个示例之前,您必须确保已按照Spring - 环境设置一章中的说明正确设置 Spring 环境。我们还假设您有一些关于 Eclipse IDE 的工作知识。
现在让我们继续编写一个简单的 Spring 应用程序,它将打印“Hello World!” 或基于 Spring Beans 配置文件中完成的配置的任何其他消息。
第 1 步 - 创建 Java 项目
第一步是使用 Eclipse IDE 创建一个简单的 Java 项目。按照选项“文件”→“新建”→“项目”,最后从向导列表中选择“Java 项目向导”。现在使用向导窗口将您的项目命名为HelloSpring,如下所示 -
成功创建项目后,您的项目资源管理器中将包含以下内容-
第 2 步 - 添加所需的库
第二步,让我们在项目中添加 Spring 框架和通用日志记录 API 库。为此,右键单击您的项目名称HelloSpring ,然后按照上下文菜单中提供的以下选项进行操作 -构建路径 → 配置构建路径以显示 Java 构建路径窗口,如下所示 -
现在,使用“库”选项卡下的“添加外部 JAR”按钮从 Spring 框架和通用日志记录安装目录添加以下核心 JAR -
公共日志记录-1.1.1
spring-aop-4.1.6.RELEASE
spring-aspects-4.1.6.RELEASE
spring-beans-4.1.6.RELEASE
spring-context-4.1.6.RELEASE
spring-context-support-4.1.6.RELEASE
spring-core-4.1.6.RELEASE
spring-表达式-4.1.6.RELEASE
spring-instrument-4.1.6.RELEASE
spring-instrument-tomcat-4.1.6.RELEASE
spring-jdbc-4.1.6.RELEASE
spring-jms-4.1.6.RELEASE
spring-messaging-4.1.6.RELEASE
spring-orm-4.1.6.RELEASE
spring-oxm-4.1.6.RELEASE
spring-test-4.1.6.RELEASE
spring-tx-4.1.6.RELEASE
spring-web-4.1.6.RELEASE
spring-webmvc-4.1.6.RELEASE
spring-webmvc-portlet-4.1.6.RELEASE
spring-websocket-4.1.6.RELEASE
第 3 步 - 创建源文件
现在让我们在HelloSpring项目下创建实际的源文件。首先我们需要创建一个名为com.tutorialspoint的包。为此,请右键单击包资源管理器部分中的src并按照选项 - New → Package。
接下来我们将在 com.tutorialspoint 包下创建HelloWorld.java和MainApp.java文件。
这是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(); } }
关于主程序,需要注意以下两个要点 -
第一步是创建一个应用程序上下文,我们在其中使用框架 API ClassPathXmlApplicationContext()。该API加载bean配置文件,并最终根据提供的API,它负责创建和初始化所有对象,即配置文件中提到的bean。
第二步是使用创建的上下文的getBean()方法获取所需的 bean。该方法使用bean ID返回一个通用对象,最终可以将其转换为实际对象。一旦你有了一个对象,你就可以使用这个对象来调用任何类方法。
第 4 步 - 创建 Bean 配置文件
您需要创建一个 Bean 配置文件,它是一个 XML 文件,充当将 Bean(即类)粘合在一起的粘合剂。该文件需要在src目录下创建,如下图所示 -
通常开发人员将此文件命名为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应用程序加载到内存中时,框架使用上面的配置文件来创建所有定义的bean,并为它们分配一个在<bean>标记中定义的唯一ID。您可以使用<property>标签来传递创建对象时使用的不同变量的值。
第 5 步 - 运行程序
创建完源文件和 beans 配置文件后,您就可以执行此步骤,即编译和运行程序。为此,请保持 MainApp.Java 文件选项卡处于活动状态,并使用Eclipse IDE 中提供的“运行”选项或使用Ctrl + F11编译并运行MainApp应用程序。如果您的应用程序一切正常,这将在 Eclipse IDE 的控制台中打印以下消息 -
Your Message : Hello World!
恭喜,您已经成功创建了您的第一个 Spring 应用程序。通过更改“message”属性的值并保持两个源文件不变,您可以看到上述 Spring 应用程序的灵活性。
Spring - IoC 容器
Spring容器是Spring框架的核心。容器将创建对象,将它们连接在一起,配置它们,并管理它们从创建到销毁的完整生命周期。Spring 容器使用 DI 来管理组成应用程序的组件。这些对象称为 Spring Bean,我们将在下一章中讨论。
容器通过读取提供的配置元数据来获取要实例化、配置和组装哪些对象的指令。配置元数据可以通过 XML、Java 注释或 Java 代码来表示。下图展示了 Spring 工作原理的高级视图。Spring IoC 容器利用 Java POJO 类和配置元数据来生成完全配置且可执行的系统或应用程序。
Spring 提供了以下两种不同类型的容器。
先生。 | 容器及描述 |
---|---|
1 | Spring BeanFactory 容器
这是为 DI 提供基本支持的最简单的容器,由org.springframework.beans.factory.BeanFactory接口定义。BeanFactory 及相关接口,如 BeanFactoryAware、InitializingBean、DisposableBean 仍然存在于 Spring 中,目的是为了向后兼容大量与 Spring 集成的第三方框架。 |
2 | Spring ApplicationContext 容器
该容器添加了更多企业特定的功能,例如从属性文件解析文本消息的能力以及将应用程序事件发布到感兴趣的事件侦听器的能力。该容器由org.springframework.context.ApplicationContext接口定义。 |
ApplicationContext容器包含BeanFactory容器的所有功能,因此通常建议使用它而不是BeanFactory。BeanFactory 仍然可以用于轻量级应用程序,例如数据量和速度都非常重要的移动设备或基于小程序的应用程序。
Spring - Bean 定义
构成应用程序主干并由 Spring IoC 容器管理的对象称为beans。bean 是一个由 Spring IoC 容器实例化、组装和管理的对象。这些 bean 是使用您提供给容器的配置元数据创建的。例如,采用 XML <bean/> 定义的形式,您已经在前面的章节中看到过。
Bean 定义包含称为配置元数据的信息,容器需要这些信息来了解以下内容 -
- 如何创建一个bean
- Bean的生命周期详细信息
- Bean的依赖关系
所有上述配置元数据都会转换为构成每个 bean 定义的一组以下属性。
先生。 | 属性及说明 |
---|---|
1 |
班级 该属性是强制性的,指定用于创建 bean 的 bean 类。 |
2 |
姓名 该属性唯一指定 bean 标识符。在基于 XML 的配置元数据中,您可以使用 id 和/或 name 属性来指定 bean 标识符。 |
3 |
范围 该属性指定从特定 bean 定义创建的对象的范围,它将在 bean 范围章节中讨论。 |
4 |
构造函数参数 这用于注入依赖项,并将在后续章节中讨论。 |
5 |
特性 这用于注入依赖项,并将在后续章节中讨论。 |
6 |
自动装配模式 这用于注入依赖项,并将在后续章节中讨论。 |
7 |
惰性初始化模式 延迟初始化的 bean 告诉 IoC 容器在第一次请求时而不是在启动时创建一个 bean 实例。 |
8 |
初始化方法 在容器设置 bean 的所有必要属性后立即调用的回调。它将在 bean 生命周期章节中讨论。 |
9 |
销毁方法 当包含 bean 的容器被销毁时要使用的回调。它将在 bean 生命周期章节中讨论。 |
Spring配置元数据
Spring IoC 容器与实际写入配置元数据的格式完全解耦。以下是向 Spring 容器提供配置元数据的三个重要方法 -
- 基于 XML 的配置文件。
- 基于注释的配置
- 基于Java的配置
您已经了解了如何向容器提供基于 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 示例来了解如何定义、配置和创建 Spring Bean。
我们将在单独的章节中讨论基于注释的配置。我们有意在单独的章节中对其进行讨论,因为我们希望您在开始使用带有注释的 Spring 依赖注入进行编程之前掌握其他一些重要的 Spring 概念。
Spring - Bean 范围
定义 <bean> 时,您可以选择声明该 bean 的范围。例如,要强制 Spring 在每次需要时生成一个新的 bean 实例,您应该将该 bean 的scope 属性声明为prototype。类似地,如果您希望 Spring 每次需要时都返回相同的 bean 实例,您应该将 bean 的范围属性声明为singleton。
Spring 框架支持以下五个范围,其中三个仅在您使用 Web 感知的 ApplicationContext 时才可用。
先生。 | 范围和描述 |
---|---|
1 |
单例 这将 bean 定义范围限定为每个 Spring IoC 容器的单个实例(默认)。 |
2 |
原型 这将单个 bean 定义范围限定为具有任意数量的对象实例。 |
3 |
要求 这将 bean 定义的范围限定为 HTTP 请求。仅在 Web 感知的 Spring ApplicationContext 上下文中有效。 |
4 |
会议 这将 bean 定义的范围限定为 HTTP 会话。仅在 Web 感知的 Spring ApplicationContext 上下文中有效。 |
5 |
全球会议 这将 bean 定义的范围限定为全局 HTTP 会话。仅在 Web 感知的 Spring ApplicationContext 上下文中有效。 |
在本章中,我们将讨论前两个范围,其余三个范围将在讨论 Web 感知的 Spring ApplicationContext 时讨论。
单例范围
如果范围设置为单例,Spring IoC 容器将创建由该 bean 定义定义的对象的一个实例。该单个实例存储在此类单例 bean 的缓存中,并且该命名 bean 的所有后续请求和引用都会返回缓存的对象。
默认范围始终是单例。但是,当您需要一个且仅一个 bean 实例时,您可以在 bean 配置文件中将范围属性设置为singleton,如以下代码片段所示 -
<!-- A bean definition with singleton scope --> <bean id = "..." class = "..." scope = "singleton"> <!-- collaborators and configuration for this bean go here --> </bean>
例子
让我们准备好一个可用的 Eclipse IDE,并按照以下步骤创建一个 Spring 应用程序 -
脚步 | 描述 |
---|---|
1 | 创建一个名为SpringExample的项目,并在创建的项目中的src文件夹下创建一个包com.tutorialspoint 。 |
2 | 使用“添加外部 JAR”选项添加所需的 Spring 库,如Spring Hello World 示例一章中所述。 |
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(); } }
以下是单例范围所需的配置文件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
原型范围
如果范围设置为prototype,则每次对该特定bean发出请求时,Spring IoC容器都会创建该对象的一个新bean实例。通常,对所有全状态 Bean 使用原型作用域,对无状态 Bean 使用单例作用域。
要定义原型范围,您可以在bean配置文件中将范围属性设置为prototype,如以下代码片段所示 -
<!-- A bean definition with prototype scope --> <bean id = "..." class = "..." scope = "prototype"> <!-- collaborators and configuration for this bean go here --> </bean>
例子
让我们准备好可用的 Eclipse IDE,并按照以下步骤创建 Spring 应用程序 -
脚步 | 描述 |
---|---|
1 | 创建一个名为SpringExample的项目,并在创建的项目中的src文件夹下创建一个包com.tutorialspoint 。 |
2 | 使用“添加外部 JAR”选项添加所需的 Spring 库,如Spring Hello World 示例一章中所述。 |
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(); } }
以下是原型范围所需的配置文件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 生命周期
Spring bean 的生命周期很容易理解。当实例化 bean 时,可能需要执行一些初始化才能使其进入可用状态。类似地,当不再需要豆并将其从容器中取出时,可能需要进行一些清理。
虽然,有在 bean 实例化和销毁之间在幕后发生的活动的列表,但本章将仅讨论 bean 初始化和销毁时需要的两个重要的 bean 生命周期回调方法。
要定义 bean 的安装和拆卸,我们只需使用initmethod和/或destroy-method参数声明 <bean> 即可。init-method 属性指定在实例化后立即在 bean 上调用的方法。类似地,destroymethod 指定在从容器中删除 bean 之前调用的方法。
初始化回调
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 } }
销毁回调
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 } }
如果您在非Web应用程序环境中使用Spring的IoC容器;例如,在富客户端桌面环境中,您可以向 JVM 注册关闭挂钩。这样做可以确保正常关闭并在单例 bean 上调用相关的销毁方法,以便释放所有资源。
建议您不要使用 InitializingBean 或 DisposableBean 回调,因为 XML 配置在命名方法方面提供了很大的灵活性。
例子
让我们准备好一个可用的 Eclipse IDE,并按照以下步骤创建一个 Spring 应用程序 -
脚步 | 描述 |
---|---|
1 | 创建一个名为SpringExample的项目,并在创建的项目中的src文件夹下创建一个包com.tutorialspoint 。 |
2 | 使用“添加外部 JAR”选项添加所需的 Spring 库,如Spring Hello World 示例一章中所述。 |
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.
默认初始化和销毁方法
如果您有太多具有相同名称的初始化和/或销毁方法的 bean,则无需在每个单独的 bean 上声明init-method和destroy-method 。相反,框架提供了使用<beans> 元素上的default-init-method和default-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 后处理器
BeanPostProcessor接口定义了回调方法,您可以实现这些方法来提供自己的实例化逻辑、依赖解析逻辑等。您还可以在 Spring 容器完成实例化、配置和初始化 Bean 后,通过插入一个或多个来实现一些自定义逻辑。 BeanPostProcessor 实现。
您可以配置多个 BeanPostProcessor 接口,并且可以通过设置order属性来控制这些 BeanPostProcessor 接口的执行顺序(前提是 BeanPostProcessor 实现了Ordered接口)。
BeanPostProcessor 对 bean(或对象)实例进行操作,这意味着 Spring IoC 容器实例化一个 bean 实例,然后 BeanPostProcessor 接口完成它们的工作。
ApplicationContext自动检测通过BeanPostProcessor接口的实现定义的任何 bean,并将这些 bean 注册为后处理器,然后在创建 bean 时由容器适当地调用。
例子
以下示例展示了如何在 ApplicationContext 的上下文中编写、注册和使用 BeanPostProcessor。
让我们准备好一个可用的 Eclipse IDE,并按照以下步骤创建一个 Spring 应用程序 -
脚步 | 描述 |
---|---|
1 | 创建一个名为SpringExample的项目,并在创建的项目中的src文件夹下创建一个包com.tutorialspoint 。 |
2 | 使用“添加外部 JAR”选项添加所需的 Spring 库,如Spring Hello World 示例一章中所述。 |
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 之前和之后实现更复杂的逻辑,因为您可以访问两个后处理器方法内的 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文件的内容。这里您需要注册一个关闭钩子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> <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定义继承
一个bean定义可以包含很多配置信息,包括构造函数参数、属性值和容器特定的信息,例如初始化方法、静态工厂方法名称等。
子 bean 定义从父定义继承配置数据。子定义可以根据需要覆盖某些值或添加其他值。
Spring Bean定义继承与Java类继承无关,但继承概念是相同的。您可以将父 bean 定义定义为模板,其他子 bean 可以从父 bean 继承所需的配置。
当您使用基于 XML 的配置元数据时,您可以使用父属性来指示子 bean 定义,并将父 bean 指定为该属性的值。
例子
让我们准备好一个可用的 Eclipse IDE,并按照以下步骤创建一个 Spring 应用程序 -
脚步 | 描述 |
---|---|
1 | 创建一个名为SpringExample的项目,并在创建的项目中的src文件夹下创建一个包com.tutorialspoint 。 |
2 | 使用“添加外部 JAR”选项添加所需的 Spring 库,如Spring Hello World 示例一章中所述。 |
3 | 在com.tutorialspoint包下创建 Java 类HelloWorld、HelloIndia和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有 Java 文件和 Bean 配置文件的内容并运行应用程序,如下所述。 |
以下是配置文件Beans.xml,其中我们定义了“helloWorld”bean,它具有两个属性message1和message2。接下来,“helloIndia”bean 已通过使用parent属性定义为“helloWorld”bean 的子级。子 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 定义模板
您可以创建一个 Bean 定义模板,其他子 Bean 定义可以使用该模板,而无需花费太多精力。在定义 Bean 定义模板时,不应指定类属性,而应指定抽象 属性,并且应指定值为true的抽象属性,如以下代码片段所示 -
<?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 - 依赖注入
每个基于 Java 的应用程序都有一些对象,它们一起工作以呈现最终用户所看到的工作应用程序。在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类并在单元测试时独立于其他类进行测试的可能性。依赖注入(有时称为连接)有助于将这些类粘合在一起,同时保持它们的独立性。
假设您有一个具有文本编辑器组件的应用程序,并且您想要提供拼写检查。你的标准代码看起来像这样 -
public class TextEditor { private SpellChecker spellChecker; public TextEditor() { spellChecker = new SpellChecker(); } }
我们在这里所做的是在文本编辑器和拼写检查器之间创建依赖关系。在控制反转场景中,我们会做这样的事情 -
public class TextEditor { private SpellChecker spellChecker; public TextEditor(SpellChecker spellChecker) { this.spellChecker = spellChecker; } }
在这里,文本编辑器不应该担心拼写检查器的实现。SpellChecker 将独立实现,并在 TextEditor 实例化时提供给 TextEditor。整个过程由 Spring 框架控制。
在这里,我们删除了 TextEditor 的完全控制,并将其保留在其他地方(即 XML 配置文件),并且依赖项(即 SpellChecker 类)通过Class Constructor注入到 TextEditor 类中。因此,控制流已被依赖注入(DI)“反转”,因为您已有效地将依赖项委托给某些外部系统。
注入依赖项的第二种方法是通过TextEditor 类的Setter 方法,我们将在其中创建一个 SpellChecker 实例。该实例将用于调用 setter 方法来初始化 TextEditor 的属性。
因此,DI 存在两种主要变体,以下两个子章节将通过示例介绍这两种变体 -
先生。 | 依赖注入类型和描述 |
---|---|
1 | 基于构造函数的依赖注入
当容器调用带有多个参数的类构造函数时,基于构造函数的 DI 就完成了,每个参数代表对另一个类的依赖。 |
2 | 基于 Setter 的依赖注入
基于 Setter 的 DI 是通过容器在调用无参构造函数或无参静态工厂方法来实例化您的 bean 后调用您的 bean 上的 setter 方法来完成的。 |
您可以混合使用基于构造函数的 DI 和基于 Setter 的 DI,但最好的经验法则是使用构造函数参数来实现强制依赖项,使用 setter 来实现可选依赖项。
使用 DI 原则,代码更加清晰,并且当对象提供其依赖项时,解耦更加有效。该对象不会查找其依赖项,也不知道依赖项的位置或类,而是一切都由 Spring 框架负责。