Spring 简明教程
Spring Framework - Overview
Spring 是一个最受欢迎的应用程序开发框架,用于企业级 Java。全世界数百万开发人员使用 Spring Framework 创建高性能、易于测试的代码,可以重复使用。
Spring is the most popular application development framework for enterprise Java. Millions of developers around the world use Spring Framework to create high performing, easily testable, and reusable code.
Spring Framework 是一个开源 Java 平台。它最初由 Rod Johnson 编写,并于 2003 年 6 月首次在 Apache 2.0 许可证下发布。
Spring framework is an open source Java platform. It was initially written by Rod Johnson and was first released under the Apache 2.0 license in June 2003.
在大小和透明度方面,Spring 是轻量级的。Spring Framework 的基本版本大约为 2MB。
Spring is lightweight when it comes to size and transparency. The basic version of Spring framework is around 2MB.
Spring Framework 的核心特性可以用在 Java 应用程序的开发中,不过有一些扩展是在 Java EE 平台基础之上构建 Web 应用程序的。Spring 框架的目标是让 J2EE 开发用起来更轻松,并通过启用基于 POJO 的编程模型来提升良好的编程实践。
The core features of the Spring Framework can be used in developing any Java application, but there are extensions for building web applications on top of the Java EE platform. Spring framework targets to make J2EE development easier to use and promotes good programming practices by enabling a POJO-based programming model.
Benefits of Using the Spring Framework
以下是使用 Spring Framework 的若干重要优势清单
Following is the list of few of the great benefits of using Spring Framework −
-
Spring enables developers to develop enterprise-class applications using POJOs. The benefit of using only POJOs is that you do not need an EJB container product such as an application server but you have the option of using only a robust servlet container such as Tomcat or some commercial product.
-
Spring is organized in a modular fashion. Even though the number of packages and classes are substantial, you have to worry only about the ones you need and ignore the rest.
-
Spring does not reinvent the wheel, instead it truly makes use of some of the existing technologies like several ORM frameworks, logging frameworks, JEE, Quartz and JDK timers, and other view technologies.
-
Testing an application written with Spring is simple because environment-dependent code is moved into this framework. Furthermore, by using JavaBeanstyle POJOs, it becomes easier to use dependency injection for injecting test data.
-
Spring’s web framework is a well-designed web MVC framework, which provides a great alternative to web frameworks such as Struts or other over-engineered or less popular web frameworks.
-
Spring provides a convenient API to translate technology-specific exceptions (thrown by JDBC, Hibernate, or JDO, for example) into consistent, unchecked exceptions.
-
Lightweight IoC containers tend to be lightweight, especially when compared to EJB containers, for example. This is beneficial for developing and deploying applications on computers with limited memory and CPU resources.
-
Spring provides a consistent transaction management interface that can scale down to a local transaction (using a single database, for example) and scale up to global transactions (using JTA, for example).
Dependency Injection (DI)
最能与 Spring 联系起来的的技术是反转控制 Dependency Injection (DI) 的特性。 Inversion of Control (IoC) 是一个通用概念,可以使用多种不同的方式来表达。依赖关系注入只是反转控制的一个具体示例。
The technology that Spring is most identified with is the Dependency Injection (DI) flavor of Inversion of Control. The Inversion of Control (IoC) is a general concept, and it can be expressed in many different ways. Dependency Injection is merely one concrete example of Inversion of Control.
在编写复杂的 Java 应用程序时,应用程序类与其它的 Java 类应该尽可能独立,以提高在单元测试时独立于其他类来重复利用和测试这些类的可能性。依赖关系注入有助于将这些类粘合在一起,并同时保持它们的独立性。
When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while unit testing. Dependency Injection helps in gluing these classes together and at the same time keeping them independent.
依赖关系注入到底是什么?让我们分别看一下这两个词。这里的依赖部分转换成了两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一下第二部分,注入。它的全部含义是,类 B 将由 IoC 注入到类 A 中。
What is dependency injection exactly? Let’s look at these two words separately. Here the dependency part translates into an association between two classes. For example, class A is dependent of class B. Now, let’s look at the second part, injection. All this means is, class B will get injected into class A by the IoC.
依赖关系注入可以通过向构造函数传递参数或通过使用 setter 方法而在构建后执行。由于依赖关系注入是 Spring 框架的核心,因此我们将在一个单独的章节中使用相关的示例来解释这个概念。
Dependency injection can happen in the way of passing parameters to the constructor or by post-construction using setter methods. As Dependency Injection is the heart of Spring Framework, we will explain this concept in a separate chapter with relevant example.
Aspect Oriented Programming (AOP)
Spring 的一个关键组件是 Aspect Oriented Programming (AOP) 框架。跨越应用程序多个点的功能被称为 cross-cutting concerns ,这些交叉关注点在概念上与应用程序的业务逻辑是分开的。包括日志记录、声明式事务、安全、缓存等在内,有各种常见良好的方面示例。
One of the key components of Spring is the Aspect Oriented Programming (AOP) framework. The functions that span multiple points of an application are called cross-cutting concerns and these cross-cutting concerns are conceptually separate from the application’s business logic. There are various common good examples of aspects including logging, declarative transactions, security, caching, etc.
面向对象编程中的模块化关键单元是类,而在面向方面编程中模块化的单元是方面。依赖关系注入有助于将应用程序对象相互解耦,而面向方面编程有助于将交叉关注点与它们影响的对象解耦。
The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. DI helps you decouple your application objects from each other, while AOP helps you decouple cross-cutting concerns from the objects that they affect.
Spring 框架的 AOP 模块提供面向切面的编程实现,使你可以定义方法拦截器和切入点,以便按部就班地解耦应该分离的功能的实现代码。我们将在一个单独的章节中进一步讨论 Spring AOP 的概念。
The AOP module of Spring Framework provides an aspect-oriented programming implementation allowing you to define method-interceptors and pointcuts to cleanly decouple code that implements functionality that should be separated. We will discuss more about Spring AOP concepts in a separate chapter.
Spring Framework - Architecture
Spring 可能是你所有企业应用程序的一站式商店。但是,Spring 是模块化的,它允许你选择和挑选哪些模块适用于你,而无需引入其余部分。以下部分提供了 Spring Framework 中所有可用模块的详细信息。
Spring could potentially be a one-stop shop for all your enterprise applications. However, Spring is modular, allowing you to pick and choose which modules are applicable to you, without having to bring in the rest. The following section provides details about all the modules available in Spring Framework.
Spring Framework 提供了大约 20 个模块,它们可以根据应用程序 requirement 使用。
The Spring Framework provides about 20 modules which can be used based on an application requirement.
Core Container
Core Container 包含 Core、Beans、Context 和 Expression Language 模块,其详细信息如下 −
The Core Container consists of the Core, Beans, Context, and Expression Language modules the details of which are as follows −
-
The Core module provides the fundamental parts of the framework, including the IoC and Dependency Injection features.
-
The Bean module provides BeanFactory, which is a sophisticated implementation of the factory pattern.
-
The Context module builds on the solid base provided by the Core and Beans modules and it is a medium to access any objects defined and configured. The ApplicationContext interface is the focal point of the Context module.
-
The SpEL module provides a powerful expression language for querying and manipulating an object graph at runtime.
Data Access/Integration
数据访问/集成层包含 JDBC、ORM、OXM、JMS 和 Transaction 模块,其详细信息如下 −
The Data Access/Integration layer consists of the JDBC, ORM, OXM, JMS and Transaction modules whose detail is as follows −
-
The JDBC module provides a JDBC-abstraction layer that removes the need for tedious JDBC related coding.
-
The ORM module provides integration layers for popular object-relational mapping APIs, including JPA, JDO, Hibernate, and iBatis.
-
The OXM module provides an abstraction layer that supports Object/XML mapping implementations for JAXB, Castor, XMLBeans, JiBX and XStream.
-
The Java Messaging Service JMS module contains features for producing and consuming messages.
-
The Transaction module supports programmatic and declarative transaction management for classes that implement special interfaces and for all your POJOs.
Web
Web 层包含 Web、Web-MVC、Web-Socket 和 Web-Portlet 模块,其详细信息如下 −
The Web layer consists of the Web, Web-MVC, Web-Socket, and Web-Portlet modules the details of which are as follows −
-
The Web module provides basic web-oriented integration features such as multipart file-upload functionality and the initialization of the IoC container using servlet listeners and a web-oriented application context.
-
The Web-MVC module contains Spring’s Model-View-Controller (MVC) implementation for web applications.
-
The Web-Socket module provides support for WebSocket-based, two-way communication between the client and the server in web applications.
-
The Web-Portlet module provides the MVC implementation to be used in a portlet environment and mirrors the functionality of Web-Servlet module.
Miscellaneous
还有几个其他重要的模块,如 AOP、Aspect、Instrumentation、Web 和 Test 模块,其详细信息如下 −
There are few other important modules like AOP, Aspects, Instrumentation, Web and Test modules the details of which are as follows −
-
The AOP module provides an aspect-oriented programming implementation allowing you to define method-interceptors and pointcuts to cleanly decouple code that implements functionality that should be separated.
-
The Aspects module provides integration with AspectJ, which is again a powerful and mature AOP framework.
-
The Instrumentation module provides class instrumentation support and class loader implementations to be used in certain application servers.
-
The Messaging module provides support for STOMP as the WebSocket sub-protocol to use in applications. It also supports an annotation programming model for routing and processing STOMP messages from WebSocket clients.
-
The Test module supports the testing of Spring components with JUnit or TestNG frameworks.
Spring - Environment Setup
本章将指导你如何准备一个开发环境来开始你使用 Spring Framework 的工作。它还将教你如何在设置 Spring Framework 之前在你的机器上设置 JDK、Tomcat 和 Eclipse −
This chapter will guide you on how to prepare a development environment to start your work with Spring Framework. It will also teach you how to set up JDK, Tomcat and Eclipse on your machine before you set up Spring Framework −
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。
You can download the latest version of SDK from Oracle’s Java site − Java SE Downloads. You will find instructions for installing JDK in downloaded files, follow the given instructions to install and configure the setup. Finally set PATH and JAVA_HOME environment variables to refer to the directory that contains java and javac, typically java_install_dir/bin and java_install_dir respectively.
如果你正在运行 Windows 并在 C:\jdk1.6.0_15 中安装了 JDK,则需要在你的 C:\autoexec.bat 文件中放入以下行。
If you are running Windows and have installed the JDK in C:\jdk1.6.0_15, you would have to put the following line in your C:\autoexec.bat file.
set PATH=C:\jdk1.6.0_15\bin;%PATH%
set JAVA_HOME=C:\jdk1.6.0_15
或者,在 Windows NT/2000/XP 中,你必须右键单击我的电脑,选择属性 → 高级 → 环境变量。然后,你将不得不更新 PATH 值并单击确定按钮。
Alternatively, on Windows NT/2000/XP, you will have to right-click on My Computer, select Properties → Advanced → Environment Variables. Then, you will have to update the PATH value and click the OK button.
在 Unix(Solaris、Linux 等)上,如果 SDK 安装在 /usr/local/jdk1.6.0_15 中,并且你使用 C shell,则必须将以下内容放入你的 .cshrc 文件中。
On Unix (Solaris, Linux, etc.), if the SDK is installed in /usr/local/jdk1.6.0_15 and you use the C shell, you will have to put the following into your .cshrc file.
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 文档中给出的内容执行正确的设置。
Alternatively, if you use an Integrated Development Environment (IDE) like Borland JBuilder, Eclipse, IntelliJ IDEA, or Sun ONE Studio, you will have to compile and run a simple program to confirm that the IDE knows where you have installed Java. Otherwise, you will have to carry out a proper setup as given in the document of the 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 文件和其他支持文档等。
You can download the latest version of Apache Commons Logging API from https://commons.apache.org/logging/. Once you download the installation, unpack the binary distribution into a convenient location. For example, in C:\commons-logging-1.1.1 on Windows, or /usr/local/commons-logging-1.1.1 on Linux/Unix. This directory will have the following jar files and other supporting documents, etc.
确保正确设置此目录上的 CLASSPATH 变量,否则在运行应用程序时会遇到问题。
Make sure you set your CLASSPATH variable on this directory properly otherwise you will face a problem while running your application.
Step 3 - Setup Eclipse IDE
本教程中的所有示例都是使用 Eclipse IDE 编写的。因此,我们建议你应该在你机器上安装 Eclipse 的最新版本。
All the examples in this tutorial have been written using Eclipse IDE. So we would suggest you should have the latest version of Eclipse installed on your machine.
要安装 Eclipse IDE,请从 https://www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压缩到方便的位置。例如,在 Windows 上的 C:\eclipse,或在 Linux/Unix 上的 /usr/local/eclipse,最后适当设置 PATH 变量。
To install Eclipse IDE, download the latest Eclipse binaries from https://www.eclipse.org/downloads/. Once you download the installation, unpack the binary distribution into a convenient location. For example, in C:\eclipse on Windows, or /usr/local/eclipse on Linux/Unix and finally set PATH variable appropriately.
可以通过在 Windows 机器上执行以下命令启动 Eclipse,或者你只需双击 eclipse.exe
Eclipse can be started by executing the following commands on Windows machine, or you can simply double-click on eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −
Eclipse can be started by executing the following commands on Unix (Solaris, Linux, etc.) machine −
$/usr/local/eclipse/eclipse
成功启动后,如果一切正常,它应该显示以下结果 −
After a successful startup, if everything is fine then it should display the following result −
Step 4 - Setup Spring Framework Libraries
现在,如果一切正常,则可以继续在你的机器上设置 Spring 框架。以下是下载和安装框架的简单步骤。
Now if everything is fine, then you can proceed to set up your Spring framework. Following are the simple steps to download and install the framework on your machine.
-
Make a choice whether you want to install Spring on Windows or Unix, and then proceed to the next step to download .zip file for Windows and .tz file for Unix.
-
Download the latest version of Spring framework binaries from https://repo.spring.io/release/org/springframework/spring.
-
At the time of developing this tutorial, spring-framework-4.1.6.RELEASE-dist.zip was downloaded on Windows machine. After the downloaded file was unzipped, it gives the following directory structure inside E:\spring.
你将在目录 E:\spring\libs 中找到所有 Spring 库。确保正确设置此目录上的 CLASSPATH 变量,否则在运行应用程序时会遇到问题。如果你正在使用 Eclipse,则不需要设置 CLASSPATH,因为所有设置都将通过 Eclipse 完成。
You will find all the Spring libraries in the directory E:\spring\libs. Make sure you set your CLASSPATH variable on this directory properly otherwise you will face a problem while running your application. If you are using Eclipse, then it is not required to set CLASSPATH because all the setting will be done through Eclipse.
一旦完成最后一步,你就可以继续在下一章中进入你的第一个 Spring 示例了。
Once you are done with this last step, you are ready to proceed to your first Spring Example in the next chapter.
Spring - Hello World Example
我们开始使用 Spring Framework 进行实际编程。在使用 Spring 框架编写第一个示例之前,你必须确保已正确设置 Spring 环境,如 Spring - Environment Setup 章节中所述。我们还假设你对 Eclipse IDE 有点了解。
Let us start actual programming with Spring Framework. Before you start writing your first example using Spring framework, you have to make sure that you have set up your Spring environment properly as explained in Spring - Environment Setup Chapter. We also assume that you have a bit of working knowledge on Eclipse IDE.
现在让我们开始编写一个简单的 Spring 应用程序,它将打印“Hello World!”或任何其他基于 Spring Bean 配置文件中所做的配置的消息。
Now let us proceed to write a simple Spring Application, which will print "Hello World!" or any other message based on the configuration done in Spring Beans Configuration file.
Step 1 - Create Java Project
第一步是使用 Eclipse IDE 创建一个简单的 Java 项目。遵循选项 File → New → Project ,最后从向导列表中选择向导 Java Project 。现在使用向导窗口将你的项目命名为 HelloSpring ,如下所示:
The first step is to create a simple Java Project using Eclipse IDE. Follow the option File → New → Project and finally select Java Project wizard from the wizard list. Now name your project as HelloSpring using the wizard window as follows −
一旦你的项目成功创建,你将在 Project Explorer 中看到以下内容:
Once your project is created successfully, you will have the following content in your Project Explorer −
Step 2 - Add Required Libraries
作为第二步,让我们在项目中添加 Spring Framework 和通用日志记录 API 库。为此,右键单击你的项目名称 HelloSpring ,然后遵循上下文菜单中提供的以下选项 Build Path → Configure Build Path ,以按如下所示显示 Java 构建路径窗口:
As a second step let us add Spring Framework and common logging API libraries in our project. To do this, right-click on your project name HelloSpring and then follow the following option available in the context menu − Build Path → Configure Build Path to display the Java Build Path window as follows −
现在使用 Libraries 选项卡下的 Add External JARs 按钮从 Spring Framework 和 Common Logging 安装目录中添加以下核心 JAR:
Now use Add External JARs button available under the Libraries tab to add the following core JARs from Spring Framework and Common Logging installation directories −
-
commons-logging-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-expression-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
Step 3 - Create Source Files
现在让我们在 HelloSpring 项目下创建实际源文件。首先,我们需要创建一个名为 com.tutorialspoint 的包。为此,右键单击包资源管理器部分中的 src ,然后按照以下选项进行操作: New → Package 。
Now let us create actual source files under the HelloSpring project. First we need to create a package called com.tutorialspoint. To do this, right click on src in package explorer section and follow the option − New → Package.
接下来,我们将在 com.tutorialspoint 包下创建 HelloWorld.java 和 MainApp.java 文件。
Next we will create HelloWorld.java and MainApp.java files under the com.tutorialspoint package.
以下是 HelloWorld.java 文件的内容 −
Here is the content of HelloWorld.java file −
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 的内容:
Following is the content of the second file 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();
}
}
关于主程序,需要注意以下两点:
Following two important points are to be noted about the main program −
-
The first step is to create an application context where we used framework API ClassPathXmlApplicationContext(). This API loads beans configuration file and eventually based on the provided API, it takes care of creating and initializing all the objects, i.e. beans mentioned in the configuration file.
-
The second step is used to get the required bean using getBean() method of the created context. This method uses bean ID to return a generic object, which finally can be casted to the actual object. Once you have an object, you can use this object to call any class method.
Step 4 - Create Bean Configuration File
你需要创建一个 Bean 配置文件,它是一个 XML 文件,充当将 Bean(即类)粘合在一起的水泥。需要在 src 目录下创建此文件,如下面的屏幕截图所示:
You need to create a Bean Configuration file which is an XML file and acts as a cement that glues the beans, i.e. the classes together. This file needs to be created under the src directory as shown in the following screenshot −
通常开发人员将此文件命名为 Beans.xml ,但你可以自由选择任何你喜欢的名称。你必须确保此文件在 CLASSPATH 中可用,并在创建应用程序上下文时在主应用程序中使用相同名称,如 MainApp.java 文件中所示。
Usually developers name this file as Beans.xml, but you are independent to choose any name you like. You have to make sure that this file is available in CLASSPATH and use the same name in the main application while creating an application context as shown in MainApp.java file.
Beans.xml 用于为不同的 bean 分配唯一 ID,并控制在不影响任何 Spring 源文件的情况下创建具有不同值的对象。例如,使用以下文件,你可以为“message”变量传递任何值,并且可以在不影响 HelloWorld.java 和 MainApp.java 文件的情况下打印消息的不同值。让我们看看它是如何工作的。
The Beans.xml is used to assign unique IDs to different beans and to control the creation of objects with different values without impacting any of the Spring source files. For example, using the following file you can pass any value for "message" variable and you can print different values of message without impacting HelloWorld.java and MainApp.java files. Let us see how it works −
<?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> 标记来传递在创建对象时使用的不同变量的值。
When Spring application gets loaded into the memory, Framework makes use of the above configuration file to create all the beans defined and assigns them a unique ID as defined in <bean> tag. You can use <property> tag to pass the values of different variables used at the time of object creation.
Step 5 - Running the Program
一旦你完成了源和 bean 配置文件的创建,你就可以进行此步骤,即编译和运行你的程序。为此,保持 MainApp.Java 文件选项卡处于活动状态,并使用 Eclipse IDE 中提供的 Run 选项或使用 Ctrl + F11 来编译和运行你的 MainApp 应用程序。如果你的应用程序一切正常,它将在 Eclipse IDE 的控制台中打印以下消息:
Once you are done with creating the source and beans configuration files, you are ready for this step, which is compiling and running your program. To do this, keep MainApp.Java file tab active and use either Run option available in the Eclipse IDE or use Ctrl + F11 to compile and run your MainApp application. If everything is fine with your application, this will print the following message in Eclipse IDE’s console −
Your Message : Hello World!
恭喜你,你已成功创建你的第一个 Spring 应用程序。你可以通过更改“message”属性的值并保持两个源文件不变来查看上述 Spring 应用程序的灵活性。
Congratulations, you have successfully created your first Spring Application. You can see the flexibility of the above Spring application by changing the value of "message" property and keeping both the source files unchanged.
Spring - IoC Containers
Spring 容器是 Spring Framework 的核心。容器将创建对象,将它们连接在一起,配置它们,并管理它们从创建到销毁的整个生命周期。Spring 容器使用 DI 来管理构成应用程序的组件。这些对象称为 Spring Bean,我们将在下一章中讨论它们。
The Spring container is at the core of the Spring Framework. The container will create the objects, wire them together, configure them, and manage their complete life cycle from creation till destruction. The Spring container uses DI to manage the components that make up an application. These objects are called Spring Beans, which we will discuss in the next chapter.
容器通过读取提供的配置元数据来获取有关实例化、配置和组装对象的指令。该配置元数据可由 XML、Java 注释或 Java 代码表示。下图展示了 Spring 的工作原理的概述图。Spring IOC 容器利用 Java POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。
The container gets its instructions on what objects to instantiate, configure, and assemble by reading the configuration metadata provided. The configuration metadata can be represented either by XML, Java annotations, or Java code. The following diagram represents a high-level view of how Spring works. The Spring IoC container makes use of Java POJO classes and configuration metadata to produce a fully configured and executable system or application.
Spring 提供了下列两种不同类型的容器。
Spring provides the following two distinct types of containers.
Sr.No. |
Container & Description |
1 |
Spring BeanFactory ContainerThis is the simplest container providing the basic support for DI and is defined by the org.springframework.beans.factory.BeanFactory interface. The BeanFactory and related interfaces, such as BeanFactoryAware, InitializingBean, DisposableBean, are still present in Spring for the purpose of backward compatibility with a large number of third-party frameworks that integrate with Spring. |
2 |
Spring ApplicationContext ContainerThis container adds more enterprise-specific functionality such as the ability to resolve textual messages from a properties file and the ability to publish application events to interested event listeners. This container is defined by the org.springframework.context.ApplicationContext interface. |
ApplicationContext 容器包含 BeanFactory 容器的所有功能,因此通常建议优于 BeanFactory。对于数据量和速度很重要的轻量级应用程序(如移动设备或基于小应用程序的应用程序),仍然可以使用 BeanFactory。
The ApplicationContext container includes all functionality of the BeanFactorycontainer, so it is generally recommended over BeanFactory. BeanFactory can still be used for lightweight applications like mobile devices or applet-based applications where data volume and speed is significant.
Spring - Bean Definition
构成应用程序主干且由 Spring IOC 容器管理的对象称为 beans 。Bean 是由 Spring IOC 容器实例化、组装和管理的对象。这些 Bean 是使用你提供给容器的配置元数据创建的。例如,在 XML <bean/> 定义中(你在前面章节中已经见过)。
The objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. These beans are created with the configuration metadata that you supply to the container. For example, in the form of XML <bean/> definitions which you have already seen in the previous chapters.
Bean 定义包含 configuration metadata 名称的信息,其中需要容器知道以下内容:
Bean definition contains the information called configuration metadata, which is needed for the container to know the following −
-
How to create a bean
-
Bean’s lifecycle details
-
Bean’s dependencies
所有以上的配置元数据都转换为一组下面的属性,该组属性构成每个 Bean 定义。
All the above configuration metadata translates into a set of the following properties that make up each bean definition.
Sr.No. |
Properties & Description |
1 |
class This attribute is mandatory and specifies the bean class to be used to create the bean. |
2 |
name This attribute specifies the bean identifier uniquely. In XMLbased configuration metadata, you use the id and/or name attributes to specify the bean identifier(s). |
3 |
scope This attribute specifies the scope of the objects created from a particular bean definition and it will be discussed in bean scopes chapter. |
4 |
constructor-arg This is used to inject the dependencies and will be discussed in subsequent chapters. |
5 |
properties This is used to inject the dependencies and will be discussed in subsequent chapters. |
6 |
autowiring mode This is used to inject the dependencies and will be discussed in subsequent chapters. |
7 |
lazy-initialization mode A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at the startup. |
8 |
initialization method A callback to be called just after all necessary properties on the bean have been set by the container. It will be discussed in bean life cycle chapter. |
9 |
destruction method A callback to be used when the container containing the bean is destroyed. It will be discussed in bean life cycle chapter. |
Spring Configuration Metadata
Spring IOC 容器完全解除了此配置元数据实际编写的格式上的限制。向 Spring 容器提供配置元数据的三种重要方法如下:
Spring IoC container is totally decoupled from the format in which this configuration metadata is actually written. Following are the three important methods to provide configuration metadata to the Spring Container −
-
XML based configuration file.
-
Annotation-based configuration
-
Java-based configuration
您已经了解了如何向容器提供基于 XML 的配置元数据,但我们来看另一个基于 XML 的配置文件示例,其中包含不同的 bean 定义,包括延迟初始化、初始化方法和销毁方法 −
You already have seen how XML-based configuration metadata is provided to the container, but let us see another sample of XML-based configuration file with different bean definitions including lazy initialization, initialization method, and destruction method −
<?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。
You can check Spring Hello World Example to understand how to define, configure and create Spring Beans.
我们将在单独的一章中讨论基于注解的配置。它是有意在单独的章节中讨论的,因为我们希望您掌握一些其他重要的 Spring 概念,然后再开始使用带注解的 Spring 依赖项注入进行编程。
We will discuss about Annotation Based Configuration in a separate chapter. It is intentionally discussed in a separate chapter as we want you to grasp a few other important Spring concepts, before you start programming with Spring Dependency Injection with Annotations.
Spring - Bean Scopes
在定义 <bean> 时,您可以选择声明该 bean 的作用域。例如,要强制 Spring 在每次需要一个 bean 实例时生成一个新的 bean 实例,您应该将 bean 的作用域属性声明为 prototype 。类似地,如果您希望 Spring 在每次需要一个 bean 实例时返回同一个 bean 实例,您应该将 bean 的作用域属性声明为 singleton 。
When defining a <bean> you have the option of declaring a scope for that bean. For example, to force Spring to produce a new bean instance each time one is needed, you should declare the bean’s scope attribute to be prototype. Similarly, if you want Spring to return the same bean instance each time one is needed, you should declare the bean’s scope attribute to be singleton.
Spring 框架支持以下五个作用域,其中三个仅在您使用 web 感知 ApplicationContext 时可用。
The Spring Framework supports the following five scopes, three of which are available only if you use a web-aware ApplicationContext.
Sr.No. |
Scope & Description |
1 |
singleton This scopes the bean definition to a single instance per Spring IoC container (default). |
2 |
prototype This scopes a single bean definition to have any number of object instances. |
3 |
request This scopes a bean definition to an HTTP request. Only valid in the context of a web-aware Spring ApplicationContext. |
4 |
session This scopes a bean definition to an HTTP session. Only valid in the context of a web-aware Spring ApplicationContext. |
5 |
global-session This scopes a bean definition to a global HTTP session. Only valid in the context of a web-aware Spring ApplicationContext. |
在本章中,我们将讨论前两个作用域,其余三个将在我们讨论 web 感知 Spring ApplicationContext 时进行讨论。
In this chapter, we will discuss about the first two scopes and the remaining three will be discussed when we discuss about web-aware Spring ApplicationContext.
The singleton scope
如果将作用域设置为 singleton,则 Spring IoC 容器会为该 bean 定义所定义的对象创建恰好一个实例。此单个实例存储在这些 singleton bean 的缓存中,并且对该已命名 bean 的所有后续请求和引用都会返回缓存对象。
If a scope is set to singleton, the Spring IoC container creates exactly one instance of the object defined by that bean definition. This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object.
默认作用域始终是单例。但是,当您只需要一个 bean 实例时,可以如以下代码片段所示在 bean 配置文件中设置 scope * property to *singleton −
The default scope is always singleton. However, when you need one and only one instance of a bean, you can set the scope * property to *singleton in the bean configuration file, as shown in the following code snippet −
<!-- A bean definition with singleton scope -->
<bean id = "..." class = "..." scope = "singleton">
<!-- collaborators and configuration for this bean go here -->
</bean>
Example
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容 −
Here is the content of HelloWorld.java file −
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 文件的内容−
Following is the content of the MainApp.java file −
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 −
Following is the configuration file Beans.xml required for singleton scope −
<?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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
Your Message : I'm object A
Your Message : I'm object A
The prototype scope
如果将作用域设置为 prototype,则 Spring IoC 容器会在每次对特定 bean 发出请求时为该对象创建一个新的 bean 实例。一般而言,将 prototype 作用域用于所有有状态 bean,将 singleton 作用域用于无状态 bean。
If the scope is set to prototype, the Spring IoC container creates a new bean instance of the object every time a request for that specific bean is made. As a rule, use the prototype scope for all state-full beans and the singleton scope for stateless beans.
要定义 prototype 作用域,可以在 bean 配置文件中将属性 scope 设置为 prototype ,如以下代码片段所示 −
To define a prototype scope, you can set the scope property to prototype in the bean configuration file, as shown in the following code snippet −
<!-- A bean definition with prototype scope -->
<bean id = "..." class = "..." scope = "prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
Example
让我们启动 Eclipse IDE 并按照以下步骤创建一个 Spring 应用程序 −
Let us have working Eclipse IDE in place and follow the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容
Here is the content of HelloWorld.java file
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 文件的内容−
Following is the content of the MainApp.java file −
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 −
Following is the configuration file Beans.xml required for prototype scope −
<?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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
Your Message : I'm object A
Your Message : null
Spring - Bean Life Cycle
Spring Bean 的生命周期很容易理解。当实例化一个 Bean 时,可能需要执行一些初始化操作使其进入可用状态。同样,当不再需要 Bean 并从容器中移除时,可能需要进行一些清理操作。
The life cycle of a Spring bean is easy to understand. When a bean is instantiated, it may be required to perform some initialization to get it into a usable state. Similarly, when the bean is no longer required and is removed from the container, some cleanup may be required.
尽管在 Bean 实例化和销毁之间的时间里有许多幕后活动列表,但本章只讨论两个重要的 Bean 生命周期回调方法,它们在 Bean 初始化和销毁时需要。
Though, there are lists of the activities that take place behind the scene between the time of bean Instantiation and its destruction, this chapter will discuss only two important bean life cycle callback methods, which are required at the time of bean initialization and its destruction.
要为 Bean 定义设置和拆除操作,我们只需使用 initmethod 和/或 destroy-method 参数声明 <bean>。init-method 属性指定一个方法,该方法在实例化后立即在 Bean 上调用。类似地,destroymethod 指定一个方法,该方法在 bean 从容器中移除之前调用。
To define setup and teardown for a bean, we simply declare the <bean> with initmethod and/or destroy-method parameters. The init-method attribute specifies a method that is to be called on the bean immediately upon instantiation. Similarly, destroymethod specifies a method that is called just before a bean is removed from the container.
Initialization callbacks
org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法 −
The org.springframework.beans.factory.InitializingBean interface specifies a single method −
void afterPropertiesSet() throws Exception;
因此,你可以简单地实现上述接口,初始化工作可以在 afterPropertiesSet() 方法中完成如下:
Thus, you can simply implement the above interface and initialization work can be done inside afterPropertiesSet() method as follows −
public class ExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}
在基于 XML 的配置文件元数据的情况下,你可以使用 init-method 属性指定具有 void 无参数签名的该方法的名称。例如 −
In the case of XML-based configuration metadata, you can use the init-method attribute to specify the name of the method that has a void no-argument signature. For example −
<bean id = "exampleBean" class = "examples.ExampleBean" init-method = "init"/>
下面的类定义 −
Following is the class definition −
public class ExampleBean {
public void init() {
// do some initialization work
}
}
Destruction callbacks
org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法 −
The org.springframework.beans.factory.DisposableBean interface specifies a single method −
void destroy() throws Exception;
因此,你可以简单地实现上述接口,最终化工作可以在 destroy() 方法中完成如下:
Thus, you can simply implement the above interface and finalization work can be done inside destroy() method as follows −
public class ExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work
}
}
在基于 XML 的配置文件元数据的情况下,你可以使用 destroy-method 属性指定具有 void 无参数签名的该方法的名称。例如 −
In the case of XML-based configuration metadata, you can use the destroy-method attribute to specify the name of the method that has a void no-argument signature. For example −
<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>
下面的类定义 −
Following is the class definition −
public class ExampleBean {
public void destroy() {
// do some destruction work
}
}
如果你在一个非网络应用程序环境中使用 Spring 的 IoC 容器,例如在富客户端桌面环境中,你要向 JVM 注册一个关闭钩子。这样做可确保正常关闭,并在你的单例 Bean 上调用相关的销毁方法,以便释放所有资源。
If you are using Spring’s IoC container in a non-web application environment; for example, in a rich client desktop environment, you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released.
建议不要使用 InitializingBean 或 DisposableBean 回调,因为 XML 配置在方法命名方面提供了很大的灵活性。
It is recommended that you do not use the InitializingBean or DisposableBean callbacks, because XML configuration gives much flexibility in terms of naming your method.
Example
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容 −
Here is the content of HelloWorld.java file −
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 类中声明。这将确保正常关闭并调用相关的销毁方法。
Following is the content of the MainApp.java file. Here you need to register a shutdown hook registerShutdownHook() method that is declared on the AbstractApplicationContext class. This will ensure a graceful shutdown and call the relevant destroy methods.
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 −
Following is the configuration file Beans.xml required for init and destroy methods −
<?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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
Bean is going through init.
Your Message : Hello World!
Bean will destroy now.
Default initialization and destroy methods
如果你有太多具有相同名称的初始化和/或销毁方法的 Bean,则无需在每个单独 Bean 上声明 init-method 和 destroy-method 。相反,框架提供了使用 <beans> 元素上的 default-init-method 和 default-destroy-method 属性配置这种情况的灵活性,如下所示 −
If you have too many beans having initialization and/or destroy methods with the same name, you don’t need to declare init-method and destroy-method on each individual bean. Instead, the framework provides the flexibility to configure such situation using default-init-method and default-destroy-method attributes on the <beans> element as follows −
<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 实现。
The BeanPostProcessor interface defines callback methods that you can implement to provide your own instantiation logic, dependency-resolution logic, etc. You can also implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean by plugging in one or more BeanPostProcessor implementations.
你可以配置多个 BeanPostProcessor 接口,并且可以通过设置 BeanPostProcessor 实现 Ordered 接口提供的 order 属性来控制这些 BeanPostProcessor 接口执行的顺序。
You can configure multiple BeanPostProcessor interfaces and you can control the order in which these BeanPostProcessor interfaces execute by setting the order property provided the BeanPostProcessor implements the Ordered interface.
在 Bean(或对象)实例上运行 BeanPostProcessor,这意味着 Spring IoC 容器实例化一个 Bean 实例,然后 BeanPostProcessor 接口执行它们的工作。
The BeanPostProcessors operate on bean (or object) instances, which means that the Spring IoC container instantiates a bean instance and then BeanPostProcessor interfaces do their work.
ApplicationContext 会自动检测以 BeanPostProcessor 接口实现为定义的任何 bean,并注册这些 bean 作为后置处理器,然后由容器在 bean 创建时适时调用。
An ApplicationContext automatically detects any beans that are defined with the implementation of the BeanPostProcessor interface and registers these beans as postprocessors, to be then called appropriately by the container upon bean creation.
Example
以下示例展示如何在 ApplicationContext 的上下文中编写、注册和使用方法 BeanPostProcessor。
The following examples show how to write, register, and use BeanPostProcessors in the context of an ApplicationContext.
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld, InitHelloWorld and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容 −
Here is the content of HelloWorld.java file −
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 对象。
This is a very basic example of implementing BeanPostProcessor, which prints a bean name before and after initialization of any bean. You can implement more complex logic before and after intializing a bean because you have access on bean object inside both the post processor methods.
以下为 InitHelloWorld.java 文件内容−
Here is the content of InitHelloWorld.java file −
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() 方法。这将确保正常关闭并调用相关的销毁方法。
Following is the content of the MainApp.java file. Here you need to register a shutdown hook registerShutdownHook() method that is declared on the AbstractApplicationContext class. This will ensures a graceful shutdown and calls the relevant destroy methods.
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 −
Following is the configuration file Beans.xml required for init and destroy methods −
<?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 配置文件,让我们运行该应用程序。如果你的应用程序一切正常,则将显示以下信息 −
Once you are done with creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.
Spring - Bean Definition Inheritance
一个 Bean 定义可以包含许多配置信息,包括构造函数参数、属性值,以及特定于容器的信息,比如初始化方法、静态工厂方法名,等等。
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on.
一个子 Bean 定义从父定义继承配置数据。子定义可以根据需要覆盖某些值,或添加其他值。
A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed.
Spring Bean 定义继承与 Java 类继承无关,但继承概念是一样的。你可以将父 Bean 定义定义为模板,其他子 Bean 可以从中继承所需的配置。
Spring Bean definition inheritance has nothing to do with Java class inheritance but the inheritance concept is same. You can define a parent bean definition as a template and other child beans can inherit the required configuration from the parent bean.
使用基于 XML 的配置元数据时,可以通过使用 parent 属性来指示一个子 Bean 定义,指定父 Bean 作为该属性的值。
When you use XML-based configuration metadata, you indicate a child bean definition by using the parent attribute, specifying the parent bean as the value of this attribute.
Example
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld, HelloIndia and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是配置文件 Beans.xml ,我们在其中定义了“helloWorld”Bean,它具有两个属性 message1 和 message2。接下来“helloIndia”Bean 已被定义为“helloWorld”Bean 的子项,方法是使用 parent 属性。该子 Bean 原样继承 message2 属性,并覆盖 message1 属性并引入一个新的 message3 属性。
Following is the configuration file Beans.xml where we defined "helloWorld" bean which has two properties message1 and message2. Next "helloIndia" bean has been defined as a child of "helloWorld" bean by using parent attribute. The child bean inherits message2 property as is, and overrides message1 property and introduces one more property 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 文件的内容 −
Here is the content of HelloWorld.java file −
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 文件的内容 −
Here is the content of HelloIndia.java file −
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 文件的内容−
Following is the content of the MainApp.java file −
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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
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 定义继承,它已经传递了。
If you observed here, we did not pass message2 while creating "helloIndia" bean, but it got passed because of Bean Definition Inheritance.
Bean Definition Template
你可以创建一个 Bean 定义模板,它可以在其他子 Bean 定义中使用,无需付出太多努力。在定义 Bean 定义模板时,你应该不要指定 class 属性,而应该指定 abstract 属性,并且应该使用 true 值指定 abstract 属性,如下面的代码片段所示 −
You can create a Bean definition template, which can be used by other child bean definitions without putting much effort. While defining a Bean Definition Template, you should not specify the class attribute and should specify abstract attribute and should specify the abstract attribute with a value of true as shown in the following code snippet −
<?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 定义使用,它作为子定义的父定义。
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract. When a definition is abstract like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions.
Spring - Dependency Injection
每个基于 Java 的应用程序都有一些对象可以协同工作,以展示最终用户所看到的工作应用程序。在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类并使其独立于其他类进行单元测试的可能性。依赖注入(或有时称为连接)有助于将这些类粘合在一起,同时又保持它们独立性。
Every Java-based application has a few objects that work together to present what the end-user sees as a working application. When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while unit testing. Dependency Injection (or sometime called wiring) helps in gluing these classes together and at the same time keeping them independent.
考虑您有一个包含文本编辑器组件的应用程序,并且您希望提供拼写检查。您的标准代码将如下所示 −
Consider you have an application which has a text editor component and you want to provide a spell check. Your standard code would look something like this −
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor() {
spellChecker = new SpellChecker();
}
}
我们在此处所做的是创建 TextEditor 和 SpellChecker 之间的依赖关系。在控制反转场景中,我们改为执行类似以下操作 −
What we’ve done here is, create a dependency between the TextEditor and the SpellChecker. In an inversion of control scenario, we would instead do something like this −
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
}
在这里,TextEditor 不应该担心 SpellChecker 实现。SpellChecker 将被独立实现,并在 TextEditor 实例化时提供给 TextEditor。此整个过程由 Spring 框架控制。
Here, the TextEditor should not worry about SpellChecker implementation. The SpellChecker will be implemented independently and will be provided to the TextEditor at the time of TextEditor instantiation. This entire procedure is controlled by the Spring Framework.
在此,我们从 TextEditor 中删除了全部控制权,并将其保存在其他地方(即 XML 配置文件),并且依赖项(即类 SpellChecker)正在通过 Class Constructor 注入到类 TextEditor 中。因此,依赖注入(DI)已经“反转”了控制流,因为您实际上已经将依赖委托给某个外部系统。
Here, we have removed total control from the TextEditor and kept it somewhere else (i.e. XML configuration file) and the dependency (i.e. class SpellChecker) is being injected into the class TextEditor through a Class Constructor. Thus the flow of control has been "inverted" by Dependency Injection (DI) because you have effectively delegated dependances to some external system.
注入依赖关系的第二种方法是通过 TextEditor 类的 Setter Methods ,我们将在其中创建 SpellChecker 实例。此实例将用于调用 setter 方法来初始化 TextEditor 的属性。
The second method of injecting dependency is through Setter Methods of the TextEditor class where we will create a SpellChecker instance. This instance will be used to call setter methods to initialize TextEditor’s properties.
因此,DI 以两种主要形式存在,以下两个小章节将用示例介绍它们 −
Thus, DI exists in two major variants and the following two sub-chapters will cover both of them with examples −
Sr.No. |
Dependency Injection Type & Description |
1 |
Constructor-based dependency injectionConstructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on the other class. |
2 |
Setter-based dependency injectionSetter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean. |
您可以混合使用基于构造函数的 DI 和基于 setter 的 DI,但一个好经验法则是对强制依赖关系使用构造函数参数,对可选依赖关系使用 setter。
You can mix both, Constructor-based and Setter-based DI but it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies.
使用 DI 原则的代码更简洁,当对象获得其依赖项时,解耦将更加有效。对象不会查找其依赖项,并且不知道依赖项的位置或类,而是 Spring 框架负责所有操作。
The code is cleaner with the DI principle and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies, rather everything is taken care by the Spring Framework.
Spring - Injecting Inner Beans
众所周知,Java 内部类在其他类的范围内内定义,类似地, inner beans 是在另一个 bean 的范围内内定义的 bean。因此,<property/> 或 <constructor-arg/> 元素中的 <bean/> 元素被称为内部 bean,如下所示。
As you know Java inner classes are defined within the scope of other classes, similarly, inner beans are beans that are defined within the scope of another bean. Thus, a <bean/> element inside the <property/> or <constructor-arg/> elements is called inner bean and it is shown below.
<?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 应用程序 −
Let us have working Eclipse IDE in place and follow the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes TextEditor, SpellChecker and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下为 TextEditor.java 文件的内容 −
Here is the content of TextEditor.java file −
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 的内容 −
Following is the content of another dependent class file 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 文件的内容−
Following is the content of the MainApp.java file −
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 进行了配置 −
Following is the configuration file Beans.xml which has configuration for the setter-based injection but using 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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.
Spring - Injecting Collection
您已经看到如何使用 Bean 配置文件中的 <property> 标记的 value 属性配置原始数据类型,以及使用 ref 属性配置对象引用。这两种情况都涉及将奇异值传递给 Bean。
You have seen how to configure primitive data type using value attribute and object references using ref attribute of the <property> tag in your Bean configuration file. Both the cases deal with passing singular value to a bean.
现在,如果您想传递复数值,如 Java 集合类型(例如列表、集合、映射和属性),该怎么办。为了处理这种情况,Spring 提供了四种类型的集合配置元素,如下所示−
Now what if you want to pass plural values like Java Collection types such as List, Set, Map, and Properties. To handle the situation, Spring offers four types of collection configuration elements which are as follows −
Sr.No |
Element & Description |
1 |
<list> This helps in wiring ie injecting a list of values, allowing duplicates. |
2 |
<set> This helps in wiring a set of values but without any duplicates. |
3 |
<map> This can be used to inject a collection of name-value pairs where name and value can be of any type. |
4 |
<props> This can be used to inject a collection of name-value pairs where the name and value are both Strings. |
您可以使用 <list> 或 <set> 来接线任何 java.util.Collection 的实现或 array 。
You can use either <list> or <set> to wire any implementation of java.util.Collection or an array.
您将遇到两种情况:(a) 传递集合的直接值和 (b) 传递 Bean 引用作为集合元素之一。
You will come across two situations (a) Passing direct values of the collection and (b) Passing a reference of a bean as one of the collection elements.
Example
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes JavaCollection, and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 JavaCollection.java 文件的内容−
Here is the content of JavaCollection.java file −
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 文件的内容−
Following is the content of the MainApp.java file −
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 ,其中包含对所有类型集合的配置−
Following is the configuration file Beans.xml which has configuration for all the type of collections −
<?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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
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 引用注入为集合的元素之一。您甚至可以将引用和值混合在一起,如下面的代码片段所示−
The following Bean definition will help you understand how to inject bean references as one of the collection’s element. Even you can mix references and values all together as shown in the following code snippet −
<?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 方法。
To use the above bean definition, you need to define your setter methods in such a way that they should be able to handle references as well.
Injecting null and empty string values
如果您需要传递一个空字符串作为值,那么您可以按如下方式传递−
If you need to pass an empty string as a value, then you can pass it as follows −
<bean id = "..." class = "exampleBean">
<property name = "email" value = ""/>
</bean>
前面的示例等效于 Java 代码:exampleBean.setEmail("")
The preceding example is equivalent to the Java code: exampleBean.setEmail("")
如果您需要传递一个 NULL 值,那么您可以按如下方式传递−
If you need to pass a NULL value, then you can pass it as follows −
<bean id = "..." class = "exampleBean">
<property name = "email"><null/></property>
</bean>
前面的示例等价于 Java 代码:exampleBean.setEmail(null)
The preceding example is equivalent to the Java code: exampleBean.setEmail(null)
Spring - Beans Auto-Wiring
你已了解如何使用 <bean> 元素声明 bean,并使用 XML 配置文件中的 <constructor-arg> 和 <property> 元素注入 <bean>。
You have learnt how to declare beans using the <bean> element and inject <bean> using <constructor-arg> and <property> elements in XML configuration file.
Spring 容器可以在不使用 <constructor-arg> 和 <property> 元素的情况下确定协作 bean 之间的关系,这有助于减少为大型基于 Spring 的应用程序编写的 XML 配置量。
The Spring container can autowire relationships between collaborating beans without using <constructor-arg> and <property> elements, which helps cut down on the amount of XML configuration you write for a big Spring-based application.
Autowiring Modes
以下是自动装配模式,可以用于指示 Spring 容器对依赖项注入使用自动装配。你可以使用 <bean/> 元素的 autowire 属性来为 bean 定义指定 autowire 模式。
Following are the autowiring modes, which can be used to instruct the Spring container to use autowiring for dependency injection. You use the autowire attribute of the <bean/> element to specify autowire mode for a bean definition.
Sr.No |
Mode & Description |
1 |
*no*This is default setting which means no autowiring and you should use explicit bean reference for wiring. You have nothing to do special for this wiring. This is what you already have seen in Dependency Injection chapter. |
2 |
byNameAutowiring by property name. Spring container looks at the properties of the beans on which autowire attribute is set to byName in the XML configuration file. It then tries to match and wire its properties with the beans defined by the same names in the configuration file. |
3 |
byTypeAutowiring by property datatype. Spring container looks at the properties of the beans on which autowire attribute is set to byType in the XML configuration file. It then tries to match and wire a property if its type matches with exactly one of the beans name in configuration file. If more than one such beans exists, a fatal exception is thrown. |
4 |
constructorSimilar to byType, but type applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. |
5 |
*autodetect*Spring first tries to wire using autowire by constructor, if it does not work, Spring tries to autowire by byType. |
你可以使用 byType 或 constructor 自动装配模式来连接数组和其他类型集合。
You can use byType or constructor autowiring mode to wire arrays and other typed-collections.
Limitations with autowiring
当在整个项目中一致使用时,自动装配效果最好。如果通常不使用自动装配,开发人员仅将其用于连接一个或两个 Bean 定义可能会令人迷惑。尽管如此,自动装配可以显著减少指定属性或构造函数参数的需要,但你应在使用自动装配前考虑其局限性和缺点。
Autowiring works best when it is used consistently across a project. If autowiring is not used in general, it might be confusing for developers to use it to wire only one or two bean definitions. Though, autowiring can significantly reduce the need to specify properties or constructor arguments but you should consider the limitations and disadvantages of autowiring before using them.
Sr.No. |
Limitations & Description |
1 |
Overriding possibility You can still specify dependencies using <constructor-arg> and <property> settings which will always override autowiring. |
2 |
Primitive data types You cannot autowire so-called simple properties such as primitives, Strings, and Classes. |
3 |
Confusing nature Autowiring is less exact than explicit wiring, so if possible prefer using explict wiring. |
Spring - Annotation Based Configuration
从 Spring 2.5 开始,可以使用 annotations 配置依赖注入成为可能。因此,与其使用 XML 来描述 Bean 装配,你可以使用对相关类、方法或字段声明的注释将 Bean 配置移到组件类本身中。
Starting from Spring 2.5 it became possible to configure the dependency injection using annotations. So instead of using XML to describe a bean wiring, you can move the bean configuration into the component class itself by using annotations on the relevant class, method, or field declaration.
注释注入在 XML 注入前执行。因此,对于通过两种方法连接的属性,后一种配置将覆盖前一种配置。
Annotation injection is performed before XML injection. Thus, the latter configuration will override the former for properties wired through both approaches.
在 Spring 容器中,注释装配不会默认启用。因此,在使用基于注释的装配之前,我们需要在 Spring 配置文件中启用它。所以如果你想在你的 Spring 应用程序中使用任何注释,请考虑以下配置文件。
Annotation wiring is not turned on in the Spring container by default. So, before we can use annotation-based wiring, we will need to enable it in our Spring configuration file. So consider the following configuration file in case you want to use any annotation in your Spring application.
<?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 应自动将值连接到属性、方法和构造函数中。让我们来看一些重要的注释以了解它们如何工作:-
Once <context:annotation-config/> is configured, you can start annotating your code to indicate that Spring should automatically wire values into properties, methods, and constructors. Let us look at a few important annotations to understand how they work −
Sr.No. |
Annotation & Description |
1 |
@RequiredThe @Required annotation applies to bean property setter methods. |
2 |
@AutowiredThe @Autowired annotation can apply to bean property setter methods, non-setter methods, constructor and properties. |
3 |
@QualifierThe @Qualifier annotation along with @Autowired can be used to remove the confusion by specifiying which exact bean will be wired. |
4 |
JSR-250 AnnotationsSpring supports JSR-250 based annotations which include @Resource, @PostConstruct and @PreDestroy annotations. |
Spring - Java Based Configuration
到目前为止,你知道我们如何使用 XML 配置文件配置 Spring Bean。如果你熟悉 XML 配置,那么真的没有必要学习如何继续基于 Java 的配置,因为你可以使用任何可用的配置来实现相同的结果。
So far you have seen how we configure Spring beans using XML configuration file. If you are comfortable with XML configuration, then it is really not required to learn how to proceed with Java-based configuration as you are going to achieve the same result using either of the configurations available.
基于 Java 的配置选项使你能够在没有 XML 的情况下编写大部分 Spring 配置,但借助本章中解释的几个基于 Java 的注释来实现。
Java-based configuration option enables you to write most of your Spring configuration without XML but with the help of few Java-based annotations explained in this chapter.
@Configuration & @Bean Annotations
使用 @Configuration 注释类表示该类可被 Spring IoC 容器用作 Bean 定义的来源。 @Bean 注释告诉 Spring 一个使用 @Bean 注释的方法将返回一个对象,该对象应注册为 Spring 应用程序上下文中的 Bean。最简单的可能的 @Configuration 类如下所示:
Annotating a class with the @Configuration indicates that the class can be used by the Spring IoC container as a source of bean definitions. The @Bean annotation tells Spring that a method annotated with @Bean will return an object that should be registered as a bean in the Spring application context. The simplest possible @Configuration class would be as follows −
package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
如上代码将等同于以下 XML 配置 -
The above code will be equivalent to the following XML configuration −
<beans>
<bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" />
</beans>
在此,用 @Bean 注释的方法名用作 bean ID,并且它创建并返回实际 bean。配置类可包含多个 @Bean 的声明。一旦定义了配置类,即可使用 AnnotationConfigApplicationContext 将它们加载并提供给 Spring 容器,如下所示 -
Here, the method name is annotated with @Bean works as bean ID and it creates and returns the actual bean. Your configuration class can have a declaration for more than one @Bean. Once your configuration classes are defined, you can load and provide them to Spring container using AnnotationConfigApplicationContext as follows −
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
helloWorld.setMessage("Hello World!");
helloWorld.getMessage();
}
可加载各个配置类,如下所示 -
You can load various configuration classes as follows −
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 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Because you are using Java-based annotations, so you also need to add CGLIB.jar from your Java installation directory and ASM.jar library which can be downloaded from asm.ow2.org. |
4 |
Create Java classes HelloWorldConfig, HelloWorld and MainApp under the com.tutorialspoint package. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorldConfig.java 文件的内容
Here is the content of HelloWorldConfig.java file
package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
@Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
以下是 HelloWorld.java 文件的内容
Here is the content of HelloWorld.java file
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 文件的内容
Following is the content of the MainApp.java file
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();
}
}
一旦完成创建所有源文件并添加了所需的附加库,即可运行应用程序。需要了解的是,不需要任何配置文件。如果一切正常,将在应用程序中打印以下消息 -
Once you are done creating all the source files and adding the required additional libraries, let us run the application. You should note that there is no configuration file required. If everything is fine with your application, it will print the following message −
Your Message : Hello World!
Injecting Bean Dependencies
当 @Bean 彼此依赖时,表达依赖关系就像让一个 bean 方法调用另一个 bean 方法一样简单,如下所示 -
When @Beans have dependencies on one another, expressing that the dependency is as simple as having one bean method calling another as follows −
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 的引用。现在,考虑另一个工作示例。
Here, the foo bean receives a reference to bar via the constructor injection. Now let us look at another working example.
Example
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Because you are using Java-based annotations, so you also need to add CGLIB.jar from your Java installation directory and ASM.jar library which can be downloaded from asm.ow2.org. |
4 |
Create Java classes TextEditorConfig, TextEditor, SpellChecker and MainApp under the com.tutorialspoint package. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 TextEditorConfig.java 文件的内容
Here is the content of TextEditorConfig.java file
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 文件的内容
Here is the content of TextEditor.java file
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 的内容
Following is the content of another dependent class file 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 文件的内容
Following is the content of the MainApp.java file
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();
}
}
一旦完成创建所有源文件并添加了所需的附加库,即可运行应用程序。需要了解的是,不需要任何配置文件。如果一切正常,将在应用程序中打印以下消息 -
Once you are done creating all the source files and adding the required additional libraries, let us run the application. You should note that there is no configuration file required. If everything is fine with your application, it will print the following message −
Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.
The @Import Annotation
@Import 注释允许从另一个配置类加载 @Bean 定义。考虑 ConfigA 类,如下所示 -
The @Import annotation allows for loading @Bean definitions from another configuration class. Consider a ConfigA class as follows −
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
可将上述 Bean 声明导入另一个 Bean 声明,如下所示 -
You can import above Bean declaration in another Bean Declaration as follows −
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
现在,与实例化上下文时需要指定 ConfigA.class 和 ConfigB.class 不同的是,只需要提供 ConfigB,如下所示 -
Now, rather than needing to specify both ConfigA.class and ConfigB.class when instantiating the context, only ConfigB needs to be supplied as follows −
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 属性 -
The @Bean annotation supports specifying arbitrary initialization and destruction callback methods, much like Spring XML’s init-method and destroy-method attributes on the bean element −
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();
}
}
Event Handling in Spring
您已在所有章节中了解到 Spring 的核心是 ApplicationContext ,它管理 bean 的完整生命周期。ApplicationContext 在加载 bean 时会发布特定类型的事件。例如,当上下文启动时,将发布 ContextStartedEvent,当上下文停止时,将发布 ContextStoppedEvent。
You have seen in all the chapters that the core of Spring is the ApplicationContext, which manages the complete life cycle of the beans. The ApplicationContext publishes certain types of events when loading the beans. For example, a ContextStartedEvent is published when the context is started and ContextStoppedEvent is published when the context is stopped.
ApplicationContext 中的事件处理通过 ApplicationEvent 类和 ApplicationListener 接口来提供。因此,如果一个 bean 实现了 ApplicationListener,那么每次一个 ApplicationEvent 被发布到 ApplicationContext 时,该 bean 都会收到通知。
Event handling in the ApplicationContext is provided through the ApplicationEvent class and ApplicationListener interface. Hence, if a bean implements the ApplicationListener, then every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified.
Spring 提供了以下标准事件 -
Spring provides the following standard events −
Sr.No. |
Spring Built-in Events & Description |
1 |
ContextRefreshedEvent This event is published when the ApplicationContext is either initialized or refreshed. This can also be raised using the refresh() method on the ConfigurableApplicationContext interface. |
2 |
ContextStartedEvent This event is published when the ApplicationContext is started using the start() method on the ConfigurableApplicationContext interface. You can poll your database or you can restart any stopped application after receiving this event. |
3 |
ContextStoppedEvent This event is published when the ApplicationContext is stopped using the stop() method on the ConfigurableApplicationContext interface. You can do required housekeep work after receiving this event. |
4 |
ContextClosedEvent This event is published when the ApplicationContext is closed using the close() method on the ConfigurableApplicationContext interface. A closed context reaches its end of life; it cannot be refreshed or restarted. |
5 |
RequestHandledEvent This is a web-specific event telling all beans that an HTTP request has been serviced. |
Spring 的事件处理是单线程的,因此如果发布一个事件,直到所有接收者收到消息,进程才会被阻止,并且流程不会继续。因此,在设计需要使用事件处理的应用程序时应小心。
Spring’s event handling is single-threaded so if an event is published, until and unless all the receivers get the message, the processes are blocked and the flow will not continue. Hence, care should be taken when designing your application if the event handling is to be used.
Listening to Context Events
为了监听上下文事件,bean 应实现 ApplicationListener 接口,该接口只有一个方法 onApplicationEvent() 。因此,让我们写一个示例来看一下事件如何传播,以及您如何将代码放在那里,以便根据某些事件执行所需的任务。
To listen to a context event, a bean should implement the ApplicationListener interface which has just one method onApplicationEvent(). So let us write an example to see how the events propagates and how you can put your code to do required task based on certain events.
让我们准备一个可用的 Eclipse IDE,然后执行以下步骤来创建一个 Spring 应用程序−
Let us have a working Eclipse IDE in place and take the following steps to create a Spring application −
Step |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create Java classes HelloWorld, CStartEventHandler, CStopEventHandler and MainApp under the com.tutorialspoint package. |
4 |
Create Beans configuration file Beans.xml under the src folder. |
5 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容
Here is the content of HelloWorld.java file
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 文件的内容
Following is the content of the CStartEventHandler.java file
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 文件的内容
Following is the content of the CStopEventHandler.java file
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 文件的内容
Following is the content of the MainApp.java file
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
Following is the configuration file 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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
ContextStartedEvent Received
Your Message : Hello World!
ContextStoppedEvent Received
如果您愿意,您可以发布自己的自定义事件,稍后您可以获取这些事件并对它们执行任何操作。如果您有兴趣编写自己的自定义事件,可以检查 Custom Events in Spring.
If you like, you can publish your own custom events and later you can capture the same to take any action against those custom events. If you are interested in writing your own custom events, you can check Custom Events in Spring.
Custom Events in Spring
编写和发布自定义事件需要进行很多步骤。遵循本章提供的指导编写、发布和处理 Custom Spring 事件。
There are number of steps to be taken to write and publish your own custom events. Follow the instructions given in this chapter to write, publish and handle Custom Spring Events.
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. All the classes will be created under this package. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Create an event class, CustomEvent by extending ApplicationEvent. This class must define a default constructor which should inherit constructor from ApplicationEvent class. |
4 |
Once your event class is defined, you can publish it from any class, let us say EventClassPublisher which implements ApplicationEventPublisherAware. You will also need to declare this class in XML configuration file as a bean so that the container can identify the bean as an event publisher because it implements the ApplicationEventPublisherAware interface. |
5 |
A published event can be handled in a class, let us say EventClassHandler which implements ApplicationListener interface and implements onApplicationEvent method for the custom event. |
6 |
Create beans configuration file Beans.xml under the src folder and a MainApp class which will work as Spring application. |
7 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
下面是 CustomEvent.java 文件的内容
Here is the content of CustomEvent.java file
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 文件的内容
Following is the content of the CustomEventPublisher.java file
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 文件的内容
Following is the content of the CustomEventHandler.java file
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 文件的内容
Following is the content of the MainApp.java file
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
Following is the configuration file 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 配置文件创建后,我们运行该应用程序。如果您的应用程序一切正常,它将打印以下消息−
Once you are done creating the source and bean configuration files, let us run the application. If everything is fine with your application, it will print the following message −
y Custom Event
y Custom Event
AOP with Spring Framework
Spring Framework 的关键组件之一是 Aspect oriented programming (AOP) 框架。面向方面编程将程序逻辑细分为称为关注点的不同部分。跨越应用程序多个点的函数称为 cross-cutting concerns ,这些跨领域关注点在概念上与应用程序的业务逻辑分离。记录、审核、声明式事务、安全、缓存等方面有很多常见的例子。
One of the key components of Spring Framework is the Aspect oriented programming (AOP) framework. Aspect-Oriented Programming entails breaking down program logic into distinct parts called so-called concerns. The functions that span multiple points of an application are called cross-cutting concerns and these cross-cutting concerns are conceptually separate from the application’s business logic. There are various common good examples of aspects like logging, auditing, declarative transactions, security, caching, etc.
面向对象编程中模块化的关键单元是类,而在面向方面编程中,模块化的单元是方面。依赖注入可帮助你解除应用程序对象之间的耦合,面向方面编程可帮助你解除跨领域关注点与它们所影响的对象之间的耦合。面向方面编程类似于 Perl、.NET、Java 和其他编程语言中的触发器。
The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Dependency Injection helps you decouple your application objects from each other and AOP helps you decouple cross-cutting concerns from the objects that they affect. AOP is like triggers in programming languages such as Perl, .NET, Java, and others.
Spring AOP 模块提供拦截器来拦截应用程序。例如,当执行方法时,你可以在方法执行之前或之后添加额外功能。
Spring AOP module provides interceptors to intercept an application. For example, when a method is executed, you can add extra functionality before or after the method execution.
AOP Terminologies
在我们开始使用面向方面编程之前,让我们熟悉面向方面编程的概念和术语。这些术语并非特定于 Spring,而是与面向方面编程相关。
Before we start working with AOP, let us become familiar with the AOP concepts and terminology. These terms are not specific to Spring, rather they are related to AOP.
Sr.No |
Terms & Description |
1 |
Aspect This is a module which has a set of APIs providing cross-cutting requirements. For example, a logging module would be called AOP aspect for logging. An application can have any number of aspects depending on the requirement. |
2 |
Join point This represents a point in your application where you can plug-in the AOP aspect. You can also say, it is the actual place in the application where an action will be taken using Spring AOP framework. |
3 |
Advice This is the actual action to be taken either before or after the method execution. This is an actual piece of code that is invoked during the program execution by Spring AOP framework. |
4 |
Pointcut This is a set of one or more join points where an advice should be executed. You can specify pointcuts using expressions or patterns as we will see in our AOP examples. |
5 |
Introduction An introduction allows you to add new methods or attributes to the existing classes. |
6 |
Target object The object being advised by one or more aspects. This object will always be a proxied object, also referred to as the advised object. |
7 |
Weaving Weaving is the process of linking aspects with other application types or objects to create an advised object. This can be done at compile time, load time, or at runtime. |
Types of Advice
@Spring 方面可使用如下所述的五种建议进行处理:
Spring aspects can work with five kinds of advice mentioned as follows −
Sr.No |
Advice & Description |
1 |
before Run advice before the a method execution. |
2 |
after Run advice after the method execution, regardless of its outcome. |
3 |
after-returning Run advice after the a method execution only if method completes successfully. |
4 |
after-throwing Run advice after the a method execution only if method exits by throwing an exception. |
5 |
around Run advice before and after the advised method is invoked. |
Custom Aspects Implementation
Spring 支持 @AspectJ annotation style 方法和 schema-based 方法来实现自定义方面。这两个方法在以下部分中已作了详细说明。
Spring supports the @AspectJ annotation style approach and the schema-based approach to implement custom aspects. These two approaches have been explained in detail in the following sections.
Sr.No |
Approach & Description |
1 |
XML Schema basedAspects are implemented using the regular classes along with XML based configuration. |
2 |
@AspectJ based@AspectJ refers to a style of declaring aspects as regular Java classes annotated with Java 5 annotations. |
Spring - JDBC Framework Overview
在处理普通老 JDBC 使用数据库时,编写不必要的代码来处理异常、打开和关闭数据库连接会变得繁琐等。然而,Spring JDBC 框架会处理所有低级别详细信息,从打开连接开始,准备并执行 SQL 语句,处理异常,处理事务,最后关闭连接。
While working with the database using plain old JDBC, it becomes cumbersome to write unnecessary code to handle exceptions, opening and closing database connections, etc. However, Spring JDBC Framework takes care of all the low-level details starting from opening the connection, prepare and execute the SQL statement, process exceptions, handle transactions and finally close the connection.
因此,您所要做的就是定义连接参数并指定要执行的 SQL 语句,并在从数据库获取数据时对每次迭代执行所需的工作。
So what you have to do is just define the connection parameters and specify the SQL statement to be executed and do the required work for each iteration while fetching data from the database.
Spring JDBC 提供了多种方法和相应的不同类来与数据库进行交互。我将采用的方法是经典的、最流行的方法,它使用框架的 JdbcTemplate 类。这是管理所有数据库通信和异常处理的中央框架类。
Spring JDBC provides several approaches and correspondingly different classes to interface with the database. I’m going to take classic and the most popular approach which makes use of JdbcTemplate class of the framework. This is the central framework class that manages all the database communication and exception handling.
JdbcTemplate Class
JDBC Template 类执行 SQL 查询、更新语句、存储过程调用、对 ResultSets 执行迭代并提取返回的参数值。它还会捕获 JDBC 异常,并将它们转换到在 org.springframework.dao 包中定义的通用、更具信息性的异常层次结构。
The JDBC Template class executes SQL queries, updates statements, stores procedure calls, performs iteration over ResultSets, and extracts returned parameter values. It also catches JDBC exceptions and translates them to the generic, more informative, exception hierarchy defined in the org.springframework.dao package.
一旦配置,JdbcTemplate 类的实例就是线程安全的。因此,您可以配置 JdbcTemplate 的一个实例,然后将此共享引用安全地注入至多个 DAO。
Instances of the JdbcTemplate class are threadsafe once configured. So you can configure a single instance of a JdbcTemplate and then safely inject this shared reference into multiple DAOs.
在使用 JDBC Template 类时的一个常见做法是在您的 Spring 配置文件中配置一个 DataSource,然后将共享 DataSource bean 依赖注入到 DAO 类中,并且在 DataSource 的 setter 中创建 JdbcTemplate。
A common practice when using the JDBC Template class is to configure a DataSource in your Spring configuration file, and then dependency-inject that shared DataSource bean into your DAO classes, and the JdbcTemplate is created in the setter for the DataSource.
Configuring Data Source
让我们在我们的数据库 TEST 中创建一个数据库表 Student 。我们假设您使用的是 MySQL 数据库,如果您使用的是任何其他数据库,则可相应地更改您的 DDL 和 SQL 查询。
Let us create a database table Student in our database TEST. We assume you are working with MySQL database, if you work with any other database then you can change your DDL and SQL queries accordingly.
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,其代码如下图所示代码片段所示:
Now we need to supply a DataSource to the JDBC Template so it can configure itself to get database access. You can configure the DataSource in the XML file with a piece of code as shown in the following code snippet −
<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 存在于提供读取和向数据库写入数据的方法,并且它们应通过一个接口暴露出此功能,应用程序的其余部分将通过此接口访问它们。
DAO stands for Data Access Object, which is commonly used for database interaction. DAOs exist to provide a means to read and write data to the database and they should expose this functionality through an interface by which the rest of the application will access them.
Spring 中的 DAO 支持可以轻松以一致方式使用像 JDBC、Hibernate、JPA 或 JDO 这样的数据访问技术。
The DAO support in Spring makes it easy to work with data access technologies like JDBC, Hibernate, JPA, or JDO in a consistent way.
Executing SQL statements
让我们了解如何使用 SQL 和 JDBC 模板对象对数据库表执行 CRUD(创建、读取、更新和删除)操作。
Let us see how we can perform CRUD (Create, Read, Update and Delete) operation on database tables using SQL and JDBC Template object.
Querying for an integer
Querying for an integer
String SQL = "select count(*) from Student";
int rowCount = jdbcTemplateObject.queryForInt( SQL );
Querying for a long
Querying for a long
String SQL = "select count(*) from Student";
long rowCount = jdbcTemplateObject.queryForLong( SQL );
A simple query using a bind variable
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
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
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
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
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
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
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 语句创建表的示例:
You can use the execute(..) method from jdbcTemplate to execute any SQL statements or DDL statements. Following is an example to use CREATE statement to create a table −
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 框架的用法:
Based on the above concepts, let us check few important examples which will help you in understanding usage of JDBC framework in Spring −
Sr.No. |
Example & Description |
1 |
Spring JDBC ExampleThis example will explain how to write a simple JDBC-based Spring application. |
2 |
SQL Stored Procedure in SpringLearn how to call SQL stored procedure while using JDBC in Spring. |
Spring - Transaction Management
数据库事务是一系列操作,它们被当作一个工作单元执行。这些操作应要么全部完成,要么完全不产生任何效果。事务管理是面向 RDBMS 的企业应用程序的重要组成部分,以确保数据完整性和一致性。事务的概念可以用以下四项关键特性来描述 ACID −
A database transaction is a sequence of actions that are treated as a single unit of work. These actions should either complete entirely or take no effect at all. Transaction management is an important part of RDBMS-oriented enterprise application to ensure data integrity and consistency. The concept of transactions can be described with the following four key properties described as ACID −
-
Atomicity − A transaction should be treated as a single unit of operation, which means either the entire sequence of operations is successful or unsuccessful.
-
Consistency − This represents the consistency of the referential integrity of the database, unique primary keys in tables, etc.
-
Isolation − There may be many transaction processing with the same data set at the same time. Each transaction should be isolated from others to prevent data corruption.
-
Durability − Once a transaction has completed, the results of this transaction have to be made permanent and cannot be erased from the database due to system failure.
真正的 RDBMS 数据库系统将为每个事务保证所有四个特性。使用 SQL 向数据库发出的事务的简单视图如下 −
A real RDBMS database system will guarantee all four properties for each transaction. The simplistic view of a transaction issued to the database using SQL is as follows −
-
Begin the transaction using begin transaction command.
-
Perform various deleted, update or insert operations using SQL queries.
-
If all the operation are successful then perform commit otherwise rollback all the operations.
Spring 框架在不同基础事务管理 API 的基础上提供了抽象层。Spring 的事务支持旨在通过向 POJO 添加事务功能来提供 EJB 事务的替代方案。Spring支持基于编程和声明的事务管理。EJB 需要应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现。
Spring framework provides an abstract layer on top of different underlying transaction management APIs. Spring’s transaction support aims to provide an alternative to EJB transactions by adding transaction capabilities to POJOs. Spring supports both programmatic and declarative transaction management. EJBs require an application server, but Spring transaction management can be implemented without the need of an application server.
Local vs. Global Transactions
本地事务特定于单个事务性资源(例如 JDBC 连接),而全局事务则可以跨越多个事务性资源(例如分布式系统中的事务)。
Local transactions are specific to a single transactional resource like a JDBC connection, whereas global transactions can span multiple transactional resources like transaction in a distributed system.
当应用程序组件和资源位于一个站点时,本地事务管理在集中计算环境中可能很有用,并且事务管理仅涉及在单台机器上运行的本地数据管理器。本地事务更容易实现。
Local transaction management can be useful in a centralized computing environment where application components and resources are located at a single site, and transaction management only involves a local data manager running on a single machine. Local transactions are easier to be implemented.
在所有资源都分布在多个系统中的分布式计算环境中需要全局事务管理。在这种情况下,需要在本地和全局级别执行事务管理。跨多个系统执行分布式或全局事务,并且其执行要求全局事务管理系统和所有相关系统的所有本地数据管理程序之间的协调。
Global transaction management is required in a distributed computing environment where all the resources are distributed across multiple systems. In such a case, transaction management needs to be done both at local and global levels. A distributed or a global transaction is executed across multiple systems, and its execution requires coordination between the global transaction management system and all the local data managers of all the involved systems.
Programmatic vs. Declarative
Spring支持两种类型的事务管理−
Spring supports two types of transaction management −
-
Programmatic transaction management − This means that you have to manage the transaction with the help of programming. That gives you extreme flexibility, but it is difficult to maintain.
-
Declarative transaction management − This means you separate transaction management from the business code. You only use annotations or XML-based configuration to manage the transactions.
声明性事务管理优于编程事务管理,尽管它不如编程事务管理灵活,而后者允许您通过代码控制事务。但作为一种横切关注点,声明性事务管理可以通过 AOP 方法模块化。Spring 通过 Spring AOP 框架支持声明性事务管理。
Declarative transaction management is preferable over programmatic transaction management though it is less flexible than programmatic transaction management, which allows you to control transactions through your code. But as a kind of crosscutting concern, declarative transaction management can be modularized with the AOP approach. Spring supports declarative transaction management through the Spring AOP framework.
Spring Transaction Abstractions
Spring 事务抽象的关键由 org.springframework.transaction.PlatformTransactionManager 接口定义,如下所示 −
The key to the Spring transaction abstraction is defined by the org.springframework.transaction.PlatformTransactionManager interface, which is as follows −
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) This method returns a currently active transaction or creates a new one, according to the specified propagation behavior. |
2 |
void commit(TransactionStatus status) This method commits the given transaction, with regard to its status. |
3 |
void rollback(TransactionStatus status) This method performs a rollback of the given transaction. |
TransactionDefinition 是 Spring 中事务支持的核心接口,定义如下 −
The TransactionDefinition is the core interface of the transaction support in Spring and it is defined as follows −
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
String getName();
int getTimeout();
boolean isReadOnly();
}
Sr.No |
Method & Description |
1 |
int getPropagationBehavior() This method returns the propagation behavior. Spring offers all of the transaction propagation options familiar from EJB CMT. |
2 |
int getIsolationLevel() This method returns the degree to which this transaction is isolated from the work of other transactions. |
3 |
String getName() This method returns the name of this transaction. |
4 |
int getTimeout() This method returns the time in seconds in which the transaction must complete. |
5 |
boolean isReadOnly() This method returns whether the transaction is read-only. |
以下是隔离级别的可能值 −
Following are the possible values for isolation level −
Sr.No |
Isolation & Description |
1 |
TransactionDefinition.ISOLATION_DEFAULT This is the default isolation level. |
2 |
TransactionDefinition.ISOLATION_READ_COMMITTED Indicates that dirty reads are prevented; non-repeatable reads and phantom reads can occur. |
3 |
TransactionDefinition.ISOLATION_READ_UNCOMMITTED Indicates that dirty reads, non-repeatable reads, and phantom reads can occur. |
4 |
TransactionDefinition.ISOLATION_REPEATABLE_READ Indicates that dirty reads and non-repeatable reads are prevented; phantom reads can occur. |
5 |
TransactionDefinition.ISOLATION_SERIALIZABLE Indicates that dirty reads, non-repeatable reads, and phantom reads are prevented. |
以下是传播类型的可能值 −
Following are the possible values for propagation types −
Sr.No. |
Propagation & Description |
1 |
TransactionDefinition.PROPAGATION_MANDATORY Supports a current transaction; throws an exception if no current transaction exists. |
2 |
*TransactionDefinition.PROPAGATION_NESTED * Executes within a nested transaction if a current transaction exists. |
3 |
*TransactionDefinition.PROPAGATION_NEVER * Does not support a current transaction; throws an exception if a current transaction exists. |
4 |
*TransactionDefinition.PROPAGATION_NOT_SUPPORTED * Does not support a current transaction; rather always execute nontransactionally. |
5 |
TransactionDefinition.PROPAGATION_REQUIRED Supports a current transaction; creates a new one if none exists. |
6 |
TransactionDefinition.PROPAGATION_REQUIRES_NEW Creates a new transaction, suspending the current transaction if one exists. |
7 |
TransactionDefinition.PROPAGATION_SUPPORTS Supports a current transaction; executes non-transactionally if none exists. |
8 |
TransactionDefinition.TIMEOUT_DEFAULT Uses the default timeout of the underlying transaction system, or none if timeouts are not supported. |
事务状态接口为事务代码提供了一种简单的方法来控制事务执行和查询事务状态。
The TransactionStatus interface provides a simple way for transactional code to control transaction execution and query transaction status.
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
boolean isCompleted();
}
Sr.No. |
Method & Description |
1 |
boolean hasSavepoint() This method returns whether this transaction internally carries a savepoint, i.e., has been created as nested transaction based on a savepoint. |
2 |
boolean isCompleted() This method returns whether this transaction is completed, i.e., whether it has already been committed or rolled back. |
3 |
boolean isNewTransaction() This method returns true in case the present transaction is new. |
4 |
boolean isRollbackOnly() This method returns whether the transaction has been marked as rollback-only. |
5 |
void setRollbackOnly() This method sets the transaction as rollback-only. |
Spring - MVC Framework
Spring Web MVC 框架提供了模型-视图-控制器 (MVC) 架构和可用作开发灵活且松散耦合的 Web 应用程序的现成组件。MVC 模式导致应用程序的不同方面(输入逻辑、业务逻辑和 UI 逻辑)分离,同时在这些元素中提供松散耦合。
The Spring Web MVC framework provides Model-View-Controller (MVC) architecture and ready components that can be used to develop flexible and loosely coupled web applications. The MVC pattern results in separating the different aspects of the application (input logic, business logic, and UI logic), while providing a loose coupling between these elements.
-
The Model encapsulates the application data and in general they will consist of POJO.
-
The View is responsible for rendering the model data and in general it generates HTML output that the client’s browser can interpret.
-
The Controller is responsible for processing user requests and building an appropriate model and passes it to the view for rendering.
The DispatcherServlet
Spring Web 模型-视图-控制器(MVC)框架围绕着处理所有 HTTP 请求和响应的 DispatcherServlet 而设计。Spring Web MVC DispatcherServlet 的请求处理工作流在以下图表中说明:
The Spring Web model-view-controller (MVC) framework is designed around a DispatcherServlet that handles all the HTTP requests and responses. The request processing workflow of the Spring Web MVC DispatcherServlet is illustrated in the following diagram −
以下为响应发送到 DispatcherServlet 的入站 HTTP 请求的事件序列 -
Following is the sequence of events corresponding to an incoming HTTP request to DispatcherServlet −
-
After receiving an HTTP request, DispatcherServlet consults the HandlerMapping to call the appropriate Controller.
-
The Controller takes the request and calls the appropriate service methods based on used GET or POST method. The service method will set model data based on defined business logic and returns view name to the DispatcherServlet.
-
The DispatcherServlet will take help from ViewResolver to pickup the defined view for the request.
-
Once view is finalized, The DispatcherServlet passes the model data to the view which is finally rendered on the browser.
所有上述组件(即 HandlerMapping、Controller 和 ViewResolver)都是 WebApplicationContext 的一部分,WebApplicationContext 是带有额外功能的 plainApplicationContext 的扩展(这些功能对于 Web 应用程序而言非常有必要)。
All the above-mentioned components, i.e. HandlerMapping, Controller, and ViewResolver are parts of WebApplicationContext which is an extension of the plainApplicationContext with some extra features necessary for web applications.
Required Configuration
您需要使用 web.xml 文件中的 URL 映射来映射您希望 DispatcherServlet 处理的请求。以下示例展示了 HelloWeb DispatcherServlet 的声明和映射 -
You need to map requests that you want the DispatcherServlet to handle, by using a URL mapping in the web.xml file. The following is an example to show declaration and mapping for HelloWeb DispatcherServlet example −
<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 。
The web.xml file will be kept in the WebContent/WEB-INF directory of your web application. Upon initialization of HelloWeb DispatcherServlet, the framework will try to load the application context from a file named [servlet-name]-servlet.xml located in the application’s WebContent/WEB-INF directory. In this case, our file will be HelloWebservlet.xml.
接下来,<servlet-mapping> 标记表明哪些 URL 将由哪个 DispatcherServlet 处理。这里,所有以 .jsp 结尾的 HTTP 请求都将由 HelloWeb DispatcherServlet 处理。
Next, <servlet-mapping> tag indicates what URLs will be handled by which DispatcherServlet. Here all the HTTP requests ending with .jsp will be handled by the HelloWeb DispatcherServlet.
如果您不想使用 [servlet-name]-servlet.xml 作为默认文件名,也不想使用 WebContent/WEB-INF 作为默认位置,您可以通过在 web.xml 文件中添加 ContextLoaderListener servlet 监听器来自定义该文件名和位置,如下所示: -
If you do not want to go with default filename as [servlet-name]-servlet.xml and default location as WebContent/WEB-INF, you can customize this file name and location by adding the servlet listener ContextLoaderListener in your web.xml file as follows −
<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 文件所需的配置: -
Now, let us check the required configuration for HelloWeb-servlet.xml file, placed in your web application’s WebContent/WEB-INF directory −
<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 文件的重要之处 -
Following are the important points about HelloWeb-servlet.xml file −
-
The [servlet-name]-servlet.xml file will be used to create the beans defined, overriding the definitions of any beans defined with the same name in the global scope.
-
The <context:component-scan…> tag will be use to activate Spring MVC annotation scanning capability which allows to make use of annotations like @Controller and @RequestMapping etc.
-
The InternalResourceViewResolver will have rules defined to resolve the view names. As per the above defined rule, a logical view named hello is delegated to a view implementation located at /WEB-INF/jsp/hello.jsp .
以下部分将向您展示如何创建您的实际组件,即 Controller、Model 和 View。
The following section will show you how to create your actual components, i.e., Controller, Model, and View.
Defining a Controller
DispatcherServlet 将请求委托给 controller 以执行特定于该请求的功能。 @Controller 注解表明特定的类扮演 controller 的角色。 @RequestMapping 注解用于将 URL 映射到整个类或特定的处理方法。
The DispatcherServlet delegates the request to the controllers to execute the functionality specific to it. The @Controller annotation indicates that a particular class serves the role of a controller. The @RequestMapping annotation is used to map a URL to either an entire class or a particular handler method.
@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 请求。
The @Controller annotation defines the class as a Spring MVC controller. Here, the first usage of @RequestMapping indicates that all handling methods on this controller are relative to the /hello path. Next annotation @RequestMapping(method = RequestMethod.GET) is used to declare the printHello() method as the controller’s default service method to handle HTTP GET request. You can define another method to handle any POST request at the same URL.
您可以用另一种形式来编写上述 controller,其中可以在 @RequestMapping 中添加附加的属性,如下所示: -
You can write the above controller in another form where you can add additional attributes in @RequestMapping as follows −
@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 请求的服务方法。下面是关于上面定义的控制器的几个要点:
The value attribute indicates the URL to which the handler method is mapped and the method attribute defines the service method to handle HTTP GET request. The following important points are to be noted about the controller defined above −
-
You will define required business logic inside a service method. You can call another method inside this method as per requirement.
-
Based on the business logic defined, you will create a model within this method. You can use setter different model attributes and these attributes will be accessed by the view to present the final result. This example creates a model with its attribute "message".
-
A defined service method can return a String, which contains the name of the view to be used to render the model. This example returns "hello" as logical view name.
Creating JSP Views
Spring MVC 支持许多类型的视图以用于不同的表示技术。其中包括有:JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 源、JasperReports 等。但是,我们最常使用带有 JSTL 的 JSP 模板。
Spring MVC supports many types of views for different presentation technologies. These include - JSPs, HTML, PDF, Excel worksheets, XML, Velocity templates, XSLT, JSON, Atom and RSS feeds, JasperReports, etc. But most commonly we use JSP templates written with JSTL.
让我们在 /WEB-INF/hello/hello.jsp 中编写一个简单的 hello 视图:
Let us write a simple hello view in /WEB-INF/hello/hello.jsp −
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
<h2>${message}</h2>
</body>
</html>
此处 ${message} 是我们在控制器中设置的属性。您可以在您的视图中显示多个属性。
Here ${message} is the attribute which we have set up inside the Controller. You can have multiple attributes to be displayed inside your view.
Spring Web MVC Framework Examples
基于上述概念,让我们查看几个重要的示例,它们将帮助您构建您的 Spring Web 应用程序:
Based on the above concepts, let us check few important examples which will help you in building your Spring Web Applications −
Sr.No. |
Example & Description |
1 |
Spring MVC Hello World ExampleThis example will explain how to write a simple Spring Web Hello World application. |
2 |
Spring MVC Form Handling ExampleThis example will explain how to write a Spring Web application using HTML forms to submit the data to the controller and display a processed result. |
3 |
Spring Page Redirection ExampleLearn how to use page redirection functionality in Spring MVC Framework. |
4 |
Spring Static Pages ExampleLearn how to access static pages along with dynamic pages in Spring MVC Framework. |
5 |
Spring Exception Handling ExampleLearn how to handle exceptions in Spring MVC Framework. |
Spring - Logging with Log4J
这是一个非常易于使用的 Spring 应用程序中的 Log4J 功能。以下示例将引导你完成一些简单的步骤,以解释 Log4J 和 Spring 之间的简单集成。
This is a very easy-to-use Log4J functionality inside Spring applications. The following example will take you through simple steps to explain the simple integration between Log4J and Spring.
我们假设你已在机器上安装了 log4J 。如果没有,则可以从 https://logging.apache.org/ 下载它,然后只需将压缩文件解压到任意文件夹中。我们只会在我们的项目中使用 log4j-x.y.z.jar 。
We assume you already have log4J installed on your machine. If you do not have it then you can download it from https://logging.apache.org/ and simply extract the zipped file in any folder. We will use only log4j-x.y.z.jar in our project.
接下来,让我们准备一个运行中的 Eclipse IDE,并按照以下步骤使用 Spring Web 框架开发基于动态表单的 Web 应用程序:
Next, let us have a working Eclipse IDE in place and take the following steps to develop a Dynamic Form-based Web Application using Spring Web Framework −
Steps |
Description |
1 |
Create a project with a name SpringExample and create a package com.tutorialspoint under the src folder in the created project. |
2 |
Add required Spring libraries using Add External JARs option as explained in the Spring Hello World Example chapter. |
3 |
Add log4j library log4j-x.y.z.jar as well in your project using using Add External JARs. |
4 |
Create Java classes HelloWorld and MainApp under the com.tutorialspoint package. |
5 |
Create Beans configuration file Beans.xml under the src folder. |
6 |
Create log4J configuration file log4j.properties under the src folder. |
7 |
The final step is to create the content of all the Java files and Bean Configuration file and run the application as explained below. |
以下是 HelloWorld.java 文件的内容
Here is the content of HelloWorld.java file
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
Following is the content of the second file 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");
}
}
您可以像生成信息消息一样生成 debug 和 error 信息。现在让我们看看 Beans.xml 文件的内容
You can generate debug and error message in a similar way as we have generated info messages. Now let us see the content of Beans.xml file
<?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 生成日志消息所需的标准规则
Following is the content of log4j.properties which defines the standard rules required for Log4J to produce log messages
# 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 控制台中打印以下消息:
Once you are done with creating source and bean configuration files, let us run the application. If everything is fine with your application, this will print the following message in Eclipse console −
Your Message : Hello World!
如果您检查 C:\\ 驱动器,那么您应该会发现日志文件 log.out ,其中包含各个日志消息,如下所示:
If you check your C:\\ drive, then you should find your log file log.out with various log messages, like something as follows −
<!-- 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 相同的方式置于您的类路径中。
Alternatively you can use Jakarta Commons Logging (JCL) API to generate a log in your Spring application. JCL can be downloaded from the https://jakarta.apache.org/commons/logging/. The only file we technically need out of this package is the commons-logging-x.y.z.jar file, which needs to be placed in your classpath in a similar way as you had put log4j-x.y.z.jar in the above example.
要使用日志记录功能,您需要 org.apache.commons.logging.Log 对象,然后您可以根据需求调用以下方法之一:
To use the logging functionality you need a org.apache.commons.logging.Log object and then you can call one of the following methods as per your requirment −
-
fatal(Object message)
-
error(Object message)
-
warn(Object message)
-
info(Object message)
-
debug(Object message)
-
trace(Object message)
以下是 MainApp.java 的替换内容,它使用 JCL API
Following is the replacement of MainApp.java, which makes use of 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 文件包含在您的项目中。
You have to make sure that you have included commons-logging-x.y.z.jar file in your project, before compiling and running the program.
现在,在上述示例中保持其余的配置和内容不变,如果您编译并运行应用程序,您将获得与使用 Log4J API 相似的结果。
Now keeping the rest of the configuration and content unchanged in the above example, if you compile and run your application, you will get a similar result as what you got using Log4J API.