1 Spring框架概述
Spring是企业Java最流行的应用程序开发框架。全球数以百万计的开发人员使用Spring Framework创建高性能,易于测试和可重用的代码。
Spring框架是一个开源的Java平台。它最初由Rod Johnson编写,并于2003年6月首次在Apache 2.0许可下发布。
当涉及到尺寸和透明度时,Spring是轻量级的。Spring框架的基本版本大约为2MB。
Spring框架的核心功能可以用于开发任何Java应用程序,但是在Java EE平台之上还可以扩展构建Web应用程序。Spring框架的目标是通过启用基于POJO的编程模型来使J2EE开发更易于使用并促进良好的编程实践。
Spring框架的优点
以下是使用Spring Framework的很多好处的列表 -
Spring使开发人员能够使用POJO开发企业级应用程序。仅使用POJO的好处在于,您不需要诸如应用程序服务器之类的EJB容器产品,但可以选择仅使用强大的servlet容器(如Tomcat或某些商业产品)。
Spring以模块化方式组织。尽管包和类的数量很大,但你只需要担心你需要的,而忽略其余的。
Spring并没有重新发明,而是真正使用了一些现有技术,如几个ORM框架,日志框架,JEE,Quartz和JDK定时器以及其他视图技术。
测试使用Spring编写的应用程序很简单,因为依赖于环境的代码已移入此框架。此外,通过使用JavaBean风格的 POJO,使用依赖注入来注入测试数据变得更加容易。
Spring的Web框架是一个设计良好的Web MVC框架,它为Web框架(如Struts或其他过度设计或不太流行的Web框架)提供了一个很好的选择。
Spring提供了一个方便的API来将特定于技术的异常(例如JDBC,Hibernate或JDO)转换为一致的未经检查的异常。
例如,轻量级IoC容器往往是轻量级的,尤其是与EJB容器相比时。这对于在内存和CPU资源有限的计算机上开发和部署应用程序很有帮助。
Spring提供了一个一致的事务管理接口,可以缩减为本地事务(例如使用单个数据库)并扩展到全局事务(例如使用JTA)。
依赖注入Dependency Injection(DI)
Spring最认同的技术是控制反转的依赖注入(DI)。该控制反转(IOC)是一个笼统的概念,它可以在许多不同的方式来表达。依赖注入仅仅是控制反转的一个具体例子。
在编写复杂的Java应用程序时,应用程序类应尽可能独立于其他Java类,以增加重用这些类的可能性,并在单元测试时独立于其他类测试它们。依赖注入有助于将这些类粘合在一起,同时保持它们独立。
完全依赖注入是什么?我们分别看这两个词。这里依赖部分转化为两个类之间的关联。例如,A类依赖于B类。现在,我们来看第二部分,注入。所有这些意思是,B类将被IoC注入A类。
依赖注入可以通过将参数传递给构造函数或通过使用setter方法进行后置构造来实现。由于依赖注入是Spring框架的核心,我们将在相关示例的单独章节中解释这个概念。
面向方面编程Aspect Oriented Programming(AOP)
Spring的关键组件之一是面向方面编程(AOP)框架。跨越应用程序多个点的功能称为横切关注点,这些横切关注点在概念上与应用程序的业务逻辑分离。有各种常见的很好的例子,包括日志记录,声明式事务,安全性,缓存等等。
OOP中模块化的关键单元是类,而在AOP中,模块化的单元是方面。DI可帮助您将应用程序对象彼此分离,而AOP可帮助您将交叉关注与其影响的对象分离开来。
Spring框架的AOP模块提供了一种面向方面的编程实现,允许您定义方法拦截器和切入点,以干净地分离实现应该分离的功能的代码。我们将在单独的章节中更多地讨论Spring AOP概念。
2 架构
Spring可能成为所有企业应用程序的一站式商店。但是,Spring是模块化的,允许您选择哪些模块适用于您,而无需引入其他模块。以下部分提供了有关Spring Framework中所有可用模块的详细信息。
Spring框架提供了大约20个模块,可以根据应用需求使用。
核心容器Core Container
核心容器由Core,Beans,Context和Expression Language模块组成,具体细节如下 -
Core模块提供了框架的基本部分,包括IOC和依赖注入特征。
Bean模块提供的BeanFactory,这是一个复杂的实现工厂模式。
Context模块建立由Core和Beans模块提供的固体基体上,它是访问定义和配置的任何对象的介质。ApplicationContext接口是Context模块的焦点。
SpEL模块提供用于查询并在运行时操作对象图的强大的表达式语言。
数据访问/集成Data Access/Integration
数据访问/集成层由JDBC,ORM,OXM,JMS和Transaction模块组成,其详细信息如下 -
JDBC模块提供了一个JDBC的抽象层,消除了冗长的JDBC相关编码的需要。
ORM模块提供的集成层为流行的对象关系映射API,包括JPA,JDO,Hibernate和iBatis。
OXM模块提供了支持用于JAXB,Castor,XMLBeans,JiBX和XStream的Object/ XML映射实现的抽象层。
Java消息传递服务JMS模块包含用于生成和使用消息的功能。
Transaction模块为所有的POJO提供编程和声明式事务管理实现特殊接口的类。
Web
Web层由Web,Web-MVC,Web-Socket和Web-Portlet模块组成,具体细节如下 -
Web模块提供了基本的面向Web的集成功能,如多文件上传功能,并使用servlet的listeners和一个面向Web的应用程序上下文IoC容器的初始化。
Web-MVC模块包含Web应用程序的Spring的模型(Model)-视图(View)-控制器(Controeller)(MVC)的实现。
Web-Socket模块提供客户端和Web应用程序服务器之间基于WebSocket的双向通信。
Web-Portlet模块提供了MVC实现在门户环境中使用,并反映了网络服务程序模块的功能。
杂项Miscellaneous
AOP,Aspects,Instrumentation,Web和Test模块等其他重要模块的细节如下 -
AOP模块提供了一个面向方面的编程实现,允许你定义方法拦截器和切入点干净地分离实现的功能,应该被分离的代码。
Aspects模块提供了与AspectJ的,这又是一个强大而成熟的AOP框架集成。
Instrumentation模块提供类工具的支持和类加载器实现在某些应用服务器使用。
Messaging模块提供STOMP作为WebSocket的子协议在应用程序中使用的支持。它还支持用于路由和处理来自WebSocket客户端的STOMP消息的注释编程模型。
Test模块支持Spring组件的使用JUnit或TestNG的框架中进行测试。
3 环境设置
本章将指导您如何准备开发环境以开始使用Spring Framework进行工作。它还将教您如何在设置Spring Framework之前在您的机器上设置JDK,Tomcat和Eclipse -
第1步 - 安装Java开发工具包(JDK)
第2步 - 安装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文件和其他支持文件等
确保你在这个目录上正确设置你的CLASSPATH变量,否则你在运行你的应用程序时会遇到问题。
第3步 - 设置Eclipse IDE
本教程中的所有示例都是使用Eclipse IDE编写的。所以我们建议你应该在你的机器上安装最新版本的Eclipse。
要安装Eclipse IDE,请从https://www.eclipse.org/downloads/下载最新的Eclipse二进制文件。下载安装后,将二进制分发包解压到方便的位置。例如,在Windows上的C:\ eclipse中,或者在Linux / Unix上的/ usr / local / eclipse上,最后设置适当的PATH变量。
Eclipse可以通过在Windows机器上执行以下命令来启动,或者您可以简单地双击eclipse.exe
%C:\eclipse\eclipse.exe
Eclipse可以通过在Unix(Solaris,Linux等)计算机上执行以下命令来启动 -
$/usr/local/eclipse/eclipse
成功启动后,如果一切正常,则应显示以下结果 -
第4步 - 设置Spring框架库
现在如果一切正常,那么你可以继续设置你的Spring框架。以下是在您的机器上下载和安装框架的简单步骤。
选择是否要在Windows或Unix上安装Spring,然后继续下一步,下载Windows的.zip文件和Unix的.tz文件。
从https://repo.spring.io/release/org/springframework/spring下载最新版本的Spring框架二进制文件。
在开发本教程时,spring-framework-4.1.6.RELEASE-dist.zip在Windows机器上下载。下载的文件解压后,它在E:\ spring中提供以下目录结构。
你会在目录E:\ spring \ libs中找到所有的Spring库。确保你在这个目录上正确设置你的CLASSPATH变量,否则你在运行你的应用程序时会遇到问题。如果您使用的是Eclipse,那么不需要设置CLASSPATH,因为所有设置都将通过Eclipse完成。
一旦完成了最后一步,就可以在下一章中继续进行第一个Spring例子了。
4 Hello World示例
让我们开始使用Spring Framework进行实际编程。在开始使用Spring框架编写第一个示例之前,您必须确保您已按照“ Spring - 环境设置章节”中的说明正确设置了Spring环境。我们还假定您在Eclipse IDE上有一些工作知识。
现在让我们继续编写一个简单的Spring应用程序,它将打印出“Hello World!”。或基于Spring Beans配置文件中配置的任何其他消息。
第1步 - 创建Java项目
第一步是使用Eclipse IDE创建一个简单的Java项目。按照选项文件(File)→新建(New)→项目(Project),最后从向导列表中选择Java Project向导。现在使用向导窗口将您的项目命名为HelloSpring,如下所示 -
一旦您的项目成功创建,您的项目浏览器(Project Explorer)中将包含以下内容-
第2步 - 添加必需的库
作为第二步,让我们在我们的项目中添加Spring Framework和通用日志API库。为此,请右键单击项目名称HelloSpring ,然后按照以下选项在上下文菜单中生成- “ 构建路径”(Build Path)→“配置构建路径”(Configure Build Path)以显示Java构建路径窗口,如下所示 -
现在使用Libraries选项卡下的Add External JARs按钮,从Spring Framework和Common Logging安装目录添加以下核心JAR -
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
第3步 - 创建源文件
现在让我们在HelloSpring项目下创建实际的源文件。首先,我们需要创建一个名为com.tutorialspoint的包。为此,请右键单击包资源管理器部分中的src,然后按照选项 - 新建(New)→打包(Package)。
接下来,我们将在com.tutorialspoint包下创建HelloWorld.java和MainApp.java文件。
这里是HelloWorld.java文件的内容-
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
以下是第二个文件MainApp.java的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); } }
关于main project需要注意以下两点:
第一步是创建一个我们使用框架API ClassPathXmlApplicationContext()的应用程序上下文。该API加载bean配置文件,并最终基于提供的API,负责创建和初始化所有对象,即配置文件中提到的bean。
第二步用于使用创建的上下文的getBean()方法获取所需的bean 。此方法使用bean ID返回一个通用对象,最终可以将其转换为实际对象。一旦你有一个对象,你可以使用这个对象来调用任何类的方法。
第4步 - 创建Bean配置文件
您需要创建一个Bean配置文件,该文件是一个XML文件,并用作粘合bean的粘合剂,即将类粘合在一起。这个文件需要在src目录下创建,如下图所示 -
通常开发者将这个文件命名为Beans.xml,但是你可以独立选择你喜欢的任何名字。您必须确保此文件在CLASSPATH中可用,并在创建应用程序上下文时在主应用程序中使用相同的名称,如MainApp.java文件中所示。
Beans.xml用于为不同的Bean分配唯一的ID,并控制具有不同值的对象的创建,而不影响任何Spring源文件。例如,使用以下文件,您可以为“message”变量传递任何值,并且可以打印不同的消息值而不影响HelloWorld.java和MainApp.java文件。让我们看看它是如何工作的 -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"> <property name = "message" value = "Hello World!"/> </bean> </beans>
当Spring应用程序被加载到内存中时,Framework使用上述配置文件创建所有定义的Bean,并为它们分配一个如<bean>标记中定义的唯一ID 。您可以使用<property>标签传递创建对象时使用的不同变量的值。
第5步 - 运行程序
完成创建源代码和Bean配置文件后,即可完成此步骤,即编译和运行程序。为此,请保持MainApp.Java文件选项卡处于活动状态,并使用Eclipse IDE中的可用Run选项或使用Ctrl + F11编译并运行您的MainApp应用程序。如果您的应用程序一切正常,这将在Eclipse IDE的控制台中显示以下消息 -
Your Message : Hello World!
恭喜,您已经成功创建了您的第一个Spring应用程序。通过更改“message”属性的值并保持两个源文件不变,您可以看到上述Spring应用程序的灵活性。
5 IoC容器
Spring容器是Spring框架的核心。容器将创建对象,将它们连接在一起,配置它们,并管理从创建到销毁的整个生命周期。Spring容器使用DI来管理组成应用程序的组件。这些对象被称为Spring Beans,我们将在下一章讨论。
容器通过读取提供的配置元数据来获取有关要实例化,配置和组装的对象的说明。配置元数据可以用XML,Java注释或Java代码表示。下图代表Spring如何工作的高级视图。Spring IoC容器使用Java POJO类和配置元数据来生成完全配置和可执行的系统或应用程序。
Spring提供了以下两种不同类型的容器。
容器和说明 | |
---|---|
1 | Spring BeanFactory Container 这是为DI提供基本支持的最简单的容器,由org.springframework.beans.factory.BeanFactory接口定义。BeanFactory和相关接口(如BeanFactoryAware,InitializingBean,DisposableBean)在Spring中仍然存在,目的是与大量与Spring集成的第三方框架向后兼容。 |
2 | Spring ApplicationContext Container 此容器添加了更多特定于企业的功能,例如从属性文件解析文本消息的能力以及将应用程序事件发布到感兴趣的事件侦听器的功能。这个容器由org.springframework.context.ApplicationContext接口定义。 |
所述的ApplicationContext容器包括所有功能的BeanFactory容器,因此,通常建议在Bean工厂。BeanFactory仍然可以用于轻量级应用程序,如移动设备或基于小应用程序的应用程序,其中数据量和速度非常重要。
6 Bean的定义
构成应用程序主干和由Spring IoC容器管理的对象称为bean。bean是一个实例化,组装并由Spring IoC容器管理的对象。这些bean是使用您提供给容器的配置元数据创建的。例如,以前面章节中已经看到的XML <bean />定义的形式。
Bean定义包含称为配置元数据的信息,这是容器知道以下内容所需的信息-
- 如何创建一个bean
- Bean的生命周期细节
- Bean的依赖关系
上述所有的配置元数据都转换成了一组构成每个bean定义的属性。
Sr.No. | 属性和说明 |
---|---|
1 | class 该属性是强制性的,并指定了用于创建bean的bean类。 |
2 | name 该属性唯一地指定了bean标识符。在基于XML的配置元数据中,您使用id和/或name属性来指定bean标识符。 |
3 | scope 这个属性指定了从特定的bean定义创建的对象的范围,它将在bean范围章节中讨论。 |
4 | constructor-arg 这用于注入依赖关系,将在后面的章节中讨论。 |
5 | properties 这用于注入依赖关系,将在后面的章节中讨论。 |
6 | autowiring mode 这用于注入依赖关系,将在后面的章节中讨论。 |
7 | lazy-initialization mode 一个懒惰初始化的bean告诉IoC容器在第一次请求时创建一个bean实例,而不是在启动时。 |
8 | initialization method 在bean的所有必要属性之后立即调用的回调已由容器设置。它将在bean生命周期章节中讨论。 |
9 | destrictopmethod 包含bean的容器被销毁时要使用的回调函数。它将在bean生命周期章节中讨论。 |
Spring元数据配置
Spring IoC容器与配置元数据实际写入的格式完全分离。以下是为Spring容器提供配置元数据的三种重要方法 -
- 基于XML的配置文件。
- 基于注释的配置
- 基于Java的配置
您已经了解了如何为容器提供基于XML的配置元数据,但让我们看到另一个带有不同bean定义的基于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"> <!-- A simple bean definition --> <bean id = "..." class = "..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- A bean definition with lazy init set on --> <bean id = "..." class = "..." lazy-init = "true"> <!-- collaborators and configuration for this bean go here --> </bean> <!-- A bean definition with initialization method --> <bean id = "..." class = "..." init-method = "..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- A bean definition with destruction method --> <bean id = "..." class = "..." destroy-method = "..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
您可以检查Spring Hello World Example来了解如何定义,配置和创建Spring Bean。
我们将在单独的章节中讨论基于注释的配置。在我们希望您掌握一些其他重要的Spring概念之前,我们将在单独的章节中对其进行有意的讨论,然后再开始使用带注释的Spring依赖注入进行编程。
7 Bean Scopes
定义一个<bean>时,你可以选择为该bean声明一个范围。例如,为了强制Spring在每次需要时产生一个新的bean实例,你应该声明bean的scope属性是原型prototype。同样,如果你希望Spring在每次需要时都返回相同的bean实例,你应该声明bean的scope属性为singleton。
Spring框架支持以下五个范围,其中三个仅在您使用Web感知的ApplicationContext时才可用。
Sr.No. | 范围和说明 |
---|---|
1 | singleton 这将bean定义的范围限定为每个Spring IoC容器的单个实例(默认值)。 |
2 | prototype 这个范围将单个bean定义为具有任意数量的对象实例。 |
3 | request 这将一个bean定义作用于HTTP请求。只有在Web感知的Spring ApplicationContext的上下文中才有效。 |
4 | session 这个bean定义了一个HTTP会话。只有在Web感知的Spring ApplicationContext的上下文中才有效。 |
5 | global-session 这个bean定义了一个全局HTTP会话。只有在Web感知的Spring ApplicationContext的上下文中才有效。 |
在本章中,我们将讨论前两个范围,其余三个将在我们讨论关于web感知的Spring ApplicationContext时讨论。
singleton scope
如果一个作用域被设置为singleton,那么Spring IoC容器恰好创建了该bean定义所定义的对象的一个实例。这个单实例存储在这些单例bean的缓存中,并且该命名bean的所有后续请求和引用都会返回缓存的对象。
默认范围始终是单例。但是,当您需要一个bean的一个且只有一个实例时,可以在bean配置文件中将scope属性设置为singleton,如以下代码片段所示 -
<!-- A bean definition with singleton scope --> <bean id = "..." class = "..." scope = "singleton"> <!-- collaborators and configuration for this bean go here --> </bean>
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
五 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容-
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
以下是MainApp.java文件的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld objA = (HelloWorld) context.getBean("helloWorld"); objA.setMessage("I'm object A"); objA.getMessage(); HelloWorld objB = (HelloWorld) context.getBean("helloWorld"); objB.getMessage(); } }
以下是单例作用域所需的配置文件Beans.xml -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" scope = "singleton"> </bean> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
Your Message : I'm object A Your Message : I'm object A
prototype scope
如果范围设置为原型,那么Spring IoC容器每次创建对该特定bean的请求时都会创建该对象的新bean实例。通常,为所有状态完全bean和无状态bean的单例作用域使用原型作用域。
要定义原型范围,您可以将范围属性设置为bean配置文件中的原型,如以下代码片段所示 -
<!-- A bean definition with prototype scope --> <bean id = "..." class = "..." scope = "prototype"> <!-- collaborators and configuration for this bean go here --> </bean>
例
让我们开始使用Eclipse IDE,并按照以下步骤创建Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
以下是MainApp.java文件的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld objA = (HelloWorld) context.getBean("helloWorld"); objA.setMessage("I'm object A"); objA.getMessage(); HelloWorld objB = (HelloWorld) context.getBean("helloWorld"); objB.getMessage(); } }
以下是原型范围所需的配置文件Beans.xml -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" scope = "prototype"> </bean> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
Your Message : I'm object A Your Message : null
8 Bean的生命周期
Spring bean的生命周期很容易理解。当一个bean被实例化时,可能需要执行一些初始化以使其进入可用状态。同样,当bean不再需要并从容器中移除时,可能需要进行一些清理。
虽然在bean Instantiation和它的销毁之间有一系列活动在本场景后面进行,本章将仅讨论两个重要的bean生命周期回调方法,这些方法在bean初始化和销毁时是必需的。
为了定义一个bean的setup和teardown,我们只需用initmethod和/或destroy-method参数声明<bean> 即可。init-method属性指定在实例化时立即在bean上调用的方法。同样,destroymethod指定了一个方法,它在从容器中移除bean之前调用。
初始化回调
org.springframework.beans.factory.InitializingBean接口指定一种方法 -
void afterPropertiesSet() throws Exception;
因此,你可以简单地实现上面的接口和初始化工作,可以在里面完成afterPropertiesSet()方法,如下所示 -
public class ExampleBean implements InitializingBean { public void afterPropertiesSet() { // do some initialization work } }
对于基于XML的配置元数据,可以使用init-method属性来指定具有void无参数签名的方法的名称。例如 -
<bean id = "exampleBean" class = "examples.ExampleBean" init-method = "init"/>
以下是班级定义 -
public class ExampleBean { public void init() { // do some initialization work } }
销毁回调
所述org.springframework.beans.factory.DisposableBean接口指定一个单一的方法-
void destroy() throws Exception;
因此,你可以简单地实现上面的接口和完成工作可以完成内部destroy()方法如下 -
public class ExampleBean implements DisposableBean { public void destroy() { // do some destruction work } }
对于基于XML的配置元数据,可以使用destroy-method属性来指定具有void无参数签名的方法的名称。例如 -
<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>
以下是班级定义 -
public class ExampleBean { public void destroy() { // do some destruction work } }
如果您在非Web应用程序环境中使用Spring的IoC容器,例如,在富客户端桌面环境中,您会向JVM注册一个关闭挂钩。这样做可以确保正常关闭并在单例bean上调用相关的销毁方法,从而释放所有资源。
建议您不要使用InitializingBean或DisposableBean回调函数,因为XML配置为命名方法提供了很大的灵活性。
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容-
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } public void init(){ System.out.println("Bean is going through init."); } public void destroy() { System.out.println("Bean will destroy now."); } }
以下是MainApp.java文件的内容。在这里你需要注册一个在AbstractApplicationContext类中声明的shutdown hook registerShutdownHook()方法。这将确保正常关机并调用相关的销毁方法。
package com.tutorialspoint; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); context.registerShutdownHook(); } }
以下是init和destroy方法所需的配置文件Beans.xml -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" init-method = "init" destroy-method = "destroy"> <property name = "message" value = "Hello World!"/> </bean> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
Bean is going through init. Your Message : Hello World! Bean will destroy now.
默认初始化和销毁方法
如果您的bean有太多具有相同名称的初始化和/或销毁方法,则无需在每个单独的bean上声明init-method和destroy-method。相反,框架提供了灵活性,可以使用<beans>元素上的default-init-method和default-destroy-method属性来配置这种情况,如下所示 -
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-init-method = "init" default-destroy-method = "destroy"> <bean id = "..." class = "..."> <!-- collaborators and configuration for this bean go here --> </bean> </beans>
9 Bean Post Processors
通过BeanPostProcessor接口定义,你可以实现提供自己的实例化逻辑,依赖解析逻辑等,您还可以实现一些自定义的逻辑Spring容器完成实例化,配置,并通过在一个或多个堵塞初始化豆后回调方法BeanPostProcessor实现。
您可以配置多个BeanPostProcessor接口,您可以通过设置BeanPostProcessor实现Ordered接口的顺序属性来控制这些BeanPostProcessor接口的执行顺序。
BeanPostProcessors对bean(或对象)实例进行操作,这意味着Spring IoC容器实例化一个bean实例,然后BeanPostProcessor接口完成它们的工作。
一个ApplicationContext自动检测任何BeanPostProcessor接口的实现定义的bean,并将这些bean注册为后处理器,然后在bean创建时由容器适当地调用它们。
例
以下示例显示了如何在ApplicationContext的上下文中编写,注册和使用BeanPostProcessors。
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld,InitHelloWorld和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容-
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } public void init(){ System.out.println("Bean is going through init."); } public void destroy(){ System.out.println("Bean will destroy now."); } }
这是实现BeanPostProcessor的一个非常基本的例子,它在任何bean的初始化之前和之后打印一个bean名称。您可以在初始化bean之前和之后实现更复杂的逻辑,因为您可以在后处理器方法中访问bean对象。
这里是InitHelloWorld.java文件的内容-
package com.tutorialspoint; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.BeansException; public class InitHelloWorld implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeforeInitialization : " + beanName); return bean; // you can return any other object as well } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("AfterInitialization : " + beanName); return bean; // you can return any other object as well } }
以下是MainApp.java文件的内容。在这里你需要注册一个在AbstractApplicationContext类中声明的shutdown hook registerShutdownHook()方法。这将确保正常关机并调用相关的销毁方法。
package com.tutorialspoint; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); context.registerShutdownHook(); } }
以下是init和destroy方法所需的配置文件Beans.xml -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" init-method = "init" destroy-method = "destroy"> <property name = "message" value = "Hello World!"/> </bean> <bean class = "com.tutorialspoint.InitHelloWorld" /> </beans>
完成创建源和配置文件后,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
BeforeInitialization : helloWorld Bean is going through init. AfterInitialization : helloWorld Your Message : Hello World! Bean will destroy now.
10 Bean定义继承
一个bean定义可以包含很多配置信息,包括构造函数参数,属性值和特定于容器的信息,例如初始化方法,静态工厂方法名称等等。
子bean定义从父定义继承配置数据。根据需要,子定义可以覆盖一些值或添加其他值。
Spring Bean定义继承与Java类继承无关,但继承概念相同。您可以将父bean定义定义为模板,其他子Bean可以从父bean继承所需的配置。
在使用基于XML的配置元数据时,通过使用父属性指定子bean定义,并指定父bean作为此属性的值。
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld,HelloIndia和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
以下是配置文件beans.xml中,我们定义的“HelloWorld”豆它有两个属性MESSAGE1和消息2。接下来,通过使用parent属性,“helloIndia”bean已被定义为“helloWorld”bean的子节点。子豆继承消息2财产是,和覆盖MESSAGE1财产,并介绍了一个更多的财产MESSAGE3。
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"> <property name = "message1" value = "Hello World!"/> <property name = "message2" value = "Hello Second World!"/> </bean> <bean id =" helloIndia" class = "com.tutorialspoint.HelloIndia" parent = "helloWorld"> <property name = "message1" value = "Hello India!"/> <property name = "message3" value = "Namaste India!"/> </bean> </beans>
这里是HelloWorld.java文件的内容-
package com.tutorialspoint; public class HelloWorld { private String message1; private String message2; public void setMessage1(String message){ this.message1 = message; } public void setMessage2(String message){ this.message2 = message; } public void getMessage1(){ System.out.println("World Message1 : " + message1); } public void getMessage2(){ System.out.println("World Message2 : " + message2); } }
这里是HelloIndia.java文件的内容-
package com.tutorialspoint; public class HelloIndia { private String message1; private String message2; private String message3; public void setMessage1(String message){ this.message1 = message; } public void setMessage2(String message){ this.message2 = message; } public void setMessage3(String message){ this.message3 = message; } public void getMessage1(){ System.out.println("India Message1 : " + message1); } public void getMessage2(){ System.out.println("India Message2 : " + message2); } public void getMessage3(){ System.out.println("India Message3 : " + message3); } }
以下是MainApp.java文件的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); HelloWorld objA = (HelloWorld) context.getBean("helloWorld"); objA.getMessage1(); objA.getMessage2(); HelloIndia objB = (HelloIndia) context.getBean("helloIndia"); objB.getMessage1(); objB.getMessage2(); objB.getMessage3(); } }
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
World Message1 : Hello World! World Message2 : Hello Second World! India Message1 : Hello India! India Message2 : Hello Second World! India Message3 : Namaste India!
如果您在这里观察到,我们在创建“helloIndia”bean时没有传递message2,但由于Bean定义继承而通过。
Bean定义模板
您可以创建一个Bean定义模板,该模板可以被其他子bean定义使用,而不需要付出太多努力。在定义Bean定义模板时,不应指定类属性,并应指定抽象 属性,并应指定值为true的抽象属性,如以下代码片段所示 -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "beanTeamplate" abstract = "true"> <property name = "message1" value = "Hello World!"/> <property name = "message2" value = "Hello Second World!"/> <property name = "message3" value = "Namaste India!"/> </bean> <bean id = "helloIndia" class = "com.tutorialspoint.HelloIndia" parent = "beanTeamplate"> <property name = "message1" value = "Hello India!"/> <property name = "message3" value = "Namaste India!"/> </bean> </beans>
父bean不能自行实例化,因为它是不完整的,并且它也明确标记为抽象。当定义像这样抽象时,它只能用作一个纯粹的模板bean定义,它充当子定义的父定义。
11 依赖注入Dependency Injection
每个基于Java的应用程序都有几个对象一起工作来展示最终用户将其看作是正在运行的应用程序。在编写复杂的Java应用程序时,应用程序类应尽可能独立于其他Java类,以增加重用这些类的可能性,并在单元测试时独立于其他类测试它们。依赖注入(或某些时候称为布线)有助于将这些类粘合在一起,同时保持它们独立。
考虑你有一个应用程序,它有一个文本编辑器组件,并且你想提供一个拼写检查。你的标准代码看起来像这样 -
public class TextEditor { private SpellChecker spellChecker; public TextEditor() { spellChecker = new SpellChecker(); } }
我们在这里所做的是,在TextEditor和SpellChecker之间创建一个依赖关系。在控制场景的倒置中,我们会做这样的事情 -
public class TextEditor { private SpellChecker spellChecker; public TextEditor(SpellChecker spellChecker) { this.spellChecker = spellChecker; } }
在这里,TextEditor不应该担心SpellChecker的实现。SpellChecker将独立实现,并将在TextEditor实例化时提供给TextEditor。整个过程由Spring框架控制。
在这里,我们已经从TextEditor中移除了总控件,并将其保留在其他地方(即XML配置文件),并且通过类构造函数将依赖项(即类SpellChecker)注入到类TextEditor中。因此,控制流量已经被依赖注入(DI)“倒置”,因为您已经有效地将依赖性委托给某个外部系统。
注入依赖的第二种方法是通过TextEditor类的Setter方法创建一个SpellChecker实例。这个实例将被用来调用setter方法来初始化TextEditor的属性。
因此,DI存在两种主要的变体,下面的两个子章节将用两个例子来介绍它们 -
依赖注入类型和描述 | |
---|---|
1 | 基于构造函数的依赖注入 当容器调用具有多个参数的类构造函数时,基于构造函数的DI就完成了,每个参数表示对另一个类的依赖关系。 |
2 | 基于Setter的依赖注入 在调用无参数构造函数或无参数静态工厂方法来实例化bean之后,基于Setter的DI通过调用bean上的容器调用setter方法来完成。 |
您可以混合使用基于构造函数和基于Setter的DI,但是对于强制性依赖关系使用构造函数参数并为可选依赖性使用设置符是一个很好的经验法则。
DI原理的代码更清晰,并且在对象提供依赖性时解耦更有效。该对象没有查找它的依赖关系,也不知道依赖关系的位置或类,所有的事情都由Spring框架来完成。
12 注入Inner Beans
正如你所知,Java内部类是在其他类的范围内定义的,类似地,内部bean是在另一个bean范围内定义的bean。因此,<property />或<constructor-arg />元素中的<bean />元素称为内部bean,如下所示。
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "outerBean" class = "..."> <property name = "target"> <bean id = "innerBean" class = "..."/> </property> </bean> </beans>
例
让我们开始使用Eclipse IDE,并按照以下步骤创建Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 创建Java类文本编辑,拼写检查和MainApp下com.tutorialspoint包。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是TextEditor.java文件的内容-
package com.tutorialspoint; public class TextEditor { private SpellChecker spellChecker; // a setter method to inject the dependency. public void setSpellChecker(SpellChecker spellChecker) { System.out.println("Inside setSpellChecker." ); this.spellChecker = spellChecker; } // a getter method to return spellChecker public SpellChecker getSpellChecker() { return spellChecker; } public void spellCheck() { spellChecker.checkSpelling(); } }
以下是另一个依赖类文件SpellChecker.java的内容 -
package com.tutorialspoint; public class SpellChecker { public SpellChecker(){ System.out.println("Inside SpellChecker constructor." ); } public void checkSpelling(){ System.out.println("Inside checkSpelling." ); } }
以下是MainApp.java文件的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); TextEditor te = (TextEditor) context.getBean("textEditor"); te.spellCheck(); } }
以下是配置文件Beans.xml,它具有基于setter的注入但使用内部bean的配置 -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- 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>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
Inside SpellChecker constructor. Inside setSpellChecker. Inside checkSpelling.
13 注入集合
你已经看到了如何使用bean配置文件中的<property>标记的ref属性使用value属性和对象引用来配置基本数据类型。这两种情况都涉及将单数值传递给bean。
现在,如果要传递像Java集合类型(如List,Set,Map和Properties)的多个值,该怎么办?为了处理这种情况,Spring提供了四种类型的集合配置元素,如下所示 -
Sr.No | 元素和说明 |
---|---|
1 | <list> 这有助于接线,即注入一个值列表,允许重复。 |
2 | <set> 这有助于连线一组值,但没有任何重复。 |
3 | <map> 这可以用于注入名称和值对可以是任何类型的集合。 |
4 | <props> 这可以用于注入名称和值均为字符串的名称 - 值对集合。 |
您可以使用<list>或<set>来连接java.util.Collection或数组的任何实现。
您将遇到两种情况(a)传递集合的直接值和(b)将bean的引用作为集合元素之一传递。
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 创建Java类JavaCollection和MainApp下com.tutorialspoint包。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是JavaCollection.java文件的内容-
package com.tutorialspoint; import java.util.*; public class JavaCollection { List addressList; Set addressSet; Map addressMap; Properties addressProp; // a setter method to set List public void setAddressList(List addressList) { this.addressList = addressList; } // prints and returns all the elements of the list. public List getAddressList() { System.out.println("List Elements :" + addressList); return addressList; } // a setter method to set Set public void setAddressSet(Set addressSet) { this.addressSet = addressSet; } // prints and returns all the elements of the Set. public Set getAddressSet() { System.out.println("Set Elements :" + addressSet); return addressSet; } // a setter method to set Map public void setAddressMap(Map addressMap) { this.addressMap = addressMap; } // prints and returns all the elements of the Map. public Map getAddressMap() { System.out.println("Map Elements :" + addressMap); return addressMap; } // a setter method to set Property public void setAddressProp(Properties addressProp) { this.addressProp = addressProp; } // prints and returns all the elements of the Property. public Properties getAddressProp() { System.out.println("Property Elements :" + addressProp); return addressProp; } }
以下是MainApp.java文件的内容-
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); JavaCollection jc=(JavaCollection)context.getBean("javaCollection"); jc.getAddressList(); jc.getAddressSet(); jc.getAddressMap(); jc.getAddressProp(); } }
以下是配置文件Beans.xml,它具有所有类型集合的配置 -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Definition for javaCollection --> <bean id = "javaCollection" class = "com.tutorialspoint.JavaCollection"> <!-- results in a setAddressList(java.util.List) call --> <property name = "addressList"> <list> <value>INDIA</value> <value>Pakistan</value> <value>USA</value> <value>USA</value> </list> </property> <!-- results in a setAddressSet(java.util.Set) call --> <property name = "addressSet"> <set> <value>INDIA</value> <value>Pakistan</value> <value>USA</value> <value>USA</value> </set> </property> <!-- results in a setAddressMap(java.util.Map) call --> <property name = "addressMap"> <map> <entry key = "1" value = "INDIA"/> <entry key = "2" value = "Pakistan"/> <entry key = "3" value = "USA"/> <entry key = "4" value = "USA"/> </map> </property> <!-- results in a setAddressProp(java.util.Properties) call --> <property name = "addressProp"> <props> <prop key = "one">INDIA</prop> <prop key = "one">INDIA</prop> <prop key = "two">Pakistan</prop> <prop key = "three">USA</prop> <prop key = "four">USA</prop> </props> </property> </bean> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
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}
注入Bean引用
以下Bean定义将帮助您了解如何将bean引用注入为集合元素之一。即使您可以将引用和值全部混合在一起,如以下代码片段所示 -
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Bean Definition to handle references and values --> <bean id = "..." class = "..."> <!-- Passing bean reference for java.util.List --> <property name = "addressList"> <list> <ref bean = "address1"/> <ref bean = "address2"/> <value>Pakistan</value> </list> </property> <!-- Passing bean reference for java.util.Set --> <property name = "addressSet"> <set> <ref bean = "address1"/> <ref bean = "address2"/> <value>Pakistan</value> </set> </property> <!-- Passing bean reference for java.util.Map --> <property name = "addressMap"> <map> <entry key = "one" value = "INDIA"/> <entry key = "two" value-ref = "address1"/> <entry key = "three" value-ref = "address2"/> </map> </property> </bean> </beans>
要使用上面的bean定义,你需要定义你的setter方法,以便它们也能够处理引用。
注入空和空字符串值
如果你需要传递一个空字符串作为值,那么你可以通过它如下 -
<bean id = "..." class = "exampleBean"> <property name = "email" value = ""/> </bean>
前面的示例等同于Java代码:exampleBean.setEmail(“”)
如果你需要传递一个NULL值,那么你可以通过它如下 -
<bean id = "..." class = "exampleBean"> <property name = "email"><null/></property> </bean>
前面的示例等同于Java代码:exampleBean.setEmail(null)
14 Beans Auto-Wiring
15 基于注释的配置
从Spring 2.5开始,使用注释配置依赖注入成为可能。因此,可以通过在相关的类,方法或字段声明中使用注释来将bean配置移动到组件类本身,而不是使用XML来描述bean配线。
注入注入是在XML注入之前执行的。因此,后者的配置将覆盖通过两种方法连接的属性的前者。
默认情况下,Spring容器中的注释接线未打开。因此,在我们使用基于注释的布线之前,我们需要在我们的Spring配置文件中启用它。因此,如果您想在Spring应用程序中使用任何注释,请考虑以下配置文件。
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:context = "http://www.springframework.org/schema/context" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <!-- bean definitions go here --> </beans>
一旦配置了<context:annotation-config />,您就可以开始注释代码,以表明Spring应该自动将值连接到属性,方法和构造函数中。让我们看看几个重要的注释来了解它们的工作原理 -
Sr.No. | 注释和说明 |
---|---|
1 | @Required @Required注解适用于bean属性设置器方法。 |
2 | @Autowired @Autowired注解可以应用于bean属性设置器方法,非设置器方法,构造器和属性。 |
3 | @Qualifier @Qualifier注释和@Autowired可以用来通过指定要连接的确切bean来消除混淆。 |
4 | JSR-250注释 Spring支持基于JSR-250的注释,包括@Resource,@PostConstruct和@PreDestroy注解。 |
16 基于Java的配置
到目前为止,您已经看到了如何使用XML配置文件来配置Spring bean。如果您对XML配置感到满意,那么实际上并不需要学习如何继续使用基于Java的配置,因为您将使用任何可用配置获得相同结果。
基于Java的配置选项使您可以在不使用XML的情况下编写大部分Spring配置,但需要借助本章中介绍的少数基于Java的注释。
@Configuration&@Bean注释
使用@Configuration注解一个类表明该类可以被Spring IoC容器用作bean定义的来源。该@Bean注解告诉Spring与@Bean注释的方法将返回应注册为Spring应用程序上下文的bean的对象。最简单的@Configuration类可能如下 -
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class HelloWorldConfig { @Bean public HelloWorld helloWorld(){ return new HelloWorld(); } }
以上代码将等同于以下XML配置 -
<beans> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld" /> </beans>
这里,方法名用@Bean作为bean ID进行注释,并创建并返回实际的bean。您的配置类可以拥有多个@Bean的声明。一旦你的配置类被定义,你可以使用AnnotationConfigApplicationContext加载并提供给Spring容器,如下所示 -
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class); HelloWorld helloWorld = ctx.getBean(HelloWorld.class); helloWorld.setMessage("Hello World!"); helloWorld.getMessage(); }
您可以按如下方式加载各种配置类:
public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class, OtherConfig.class); ctx.register(AdditionalConfig.class); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 因为您使用的是基于Java的批注,所以您还需要从Java安装目录和ASM.jar库中添加CGLIB.jar,该库可以从asm.ow2.org下载。 |
4 | 在com.tutorialspoint包下创建Java类HelloWorldConfig,HelloWorld和MainApp。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorldConfig.java文件的内容
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class HelloWorldConfig { @Bean public HelloWorld helloWorld(){ return new HelloWorld(); } }
这里是HelloWorld.java文件的内容
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
以下是MainApp.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.*; public class MainApp { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class); HelloWorld helloWorld = ctx.getBean(HelloWorld.class); helloWorld.setMessage("Hello World!"); helloWorld.getMessage(); } }
完成所有源文件的创建并添加所需的其他库之后,让我们运行该应用程序。您应该注意,不需要配置文件。如果你的应用程序一切正常,它会打印下面的消息 -
Your Message : Hello World!
注入Bean依赖关系
当@Beans彼此依赖时,表达依赖性就像调用另一个bean方法一样简单,如下所示 -
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class AppConfig { @Bean public Foo foo() { return new Foo(bar()); } @Bean public Bar bar() { return new Bar(); } }
这里,foo bean通过构造函数注入接收对bar的引用。现在让我们看看另一个工作示例。
例
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 因为您使用的是基于Java的批注,所以您还需要从Java安装目录和ASM.jar库中添加CGLIB.jar,该库可以从asm.ow2.org下载。 |
4 | 创建Java类TextEditorConfig,文本编辑,拼写检查和MainApp下com.tutorialspoint包。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是TextEditorConfig.java文件的内容
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class TextEditorConfig { @Bean public TextEditor textEditor(){ return new TextEditor( spellChecker() ); } @Bean public SpellChecker spellChecker(){ return new SpellChecker( ); } }
这里是TextEditor.java文件的内容
package com.tutorialspoint; public class TextEditor { private SpellChecker spellChecker; public TextEditor(SpellChecker spellChecker){ System.out.println("Inside TextEditor constructor." ); this.spellChecker = spellChecker; } public void spellCheck(){ spellChecker.checkSpelling(); } }
以下是另一个依赖类文件SpellChecker.java的内容
package com.tutorialspoint; public class SpellChecker { public SpellChecker(){ System.out.println("Inside SpellChecker constructor." ); } public void checkSpelling(){ System.out.println("Inside checkSpelling." ); } }
以下是MainApp.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.*; public class MainApp { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(TextEditorConfig.class); TextEditor te = ctx.getBean(TextEditor.class); te.spellCheck(); } }
完成所有源文件的创建并添加所需的其他库之后,让我们运行该应用程序。您应该注意,不需要配置文件。如果你的应用程序一切正常,它会打印下面的消息 -
Inside SpellChecker constructor. Inside TextEditor constructor. Inside checkSpelling.
@Import注释
该@Import注释允许从另一个配置类加载@Bean定义。考虑如下的ConfigA类 -
@Configuration public class ConfigA { @Bean public A a() { return new A(); } }
你可以在另一个Bean声明中导入上面的Bean声明,如下所示 -
@Configuration @Import(ConfigA.class) public class ConfigB { @Bean public B a() { return new A(); } }
现在,不需要在实例化上下文时指定ConfigA.class和ConfigB.class,只需要提供ConfigB,如下所示 -
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class); // now both beans A and B will be available... A a = ctx.getBean(A.class); B b = ctx.getBean(B.class); }
生命周期回调
@Bean注解支持指定任意初始化和销毁回调方法,就像Spring XML的bean元素的init-method和destroy-method属性一样 -
public class Foo { public void init() { // initialization logic } public void cleanup() { // destruction logic } } @Configuration public class AppConfig { @Bean(initMethod = "init", destroyMethod = "cleanup" ) public Foo foo() { return new Foo(); } }
指定Bean范围
默认范围是单例,但您可以使用@Scope注释覆盖它,如下所示 -
@Configuration public class AppConfig { @Bean @Scope("prototype") public Foo foo() { return new Foo(); } }
17 Spring中的事件处理
您在所有章节都看到,Spring的核心是ApplicationContext,它管理bean的整个生命周期。ApplicationContext在加载Bean时发布某些类型的事件。例如,ContextStartedEvent在上下文启动时发布,而ContextStoppedEvent在上下文停止时发布。
ApplicationContext中的事件处理通过ApplicationEvent类和ApplicationListener接口提供。因此,如果一个bean实现了ApplicationListener,那么每当一个ApplicationEvent被发布到ApplicationContext时,该bean就会被通知。
Spring提供了以下标准事件 -
Spring内置事件和描述 | |
---|---|
1 | ContextRefreshedEvent 此事件在ApplicationContext被初始化或刷新时发布。这也可以使用ConfigurableApplicationContext接口上的refresh()方法引发。 |
2 | ContextStartedEvent 使用ConfigurableApplicationContext接口上的start()方法启动ApplicationContext时,会发布此事件。您可以轮询您的数据库,也可以在收到此事件后重新启动任何停止的应用程序 |
3 | ContextStoppedEvent 使用ConfigurableApplicationContext接口上的stop()方法停止ApplicationContext时发布此事件。收到此事件后,您可以做所需的管家工作。 |
4 | ContextClosedEvent 使用ConfigurableApplicationContext接口上的close()方法关闭ApplicationContext时发布此事件。封闭的环境达到其生命的尽头; 它不能被刷新或重新启动。 |
5 | RequestHandledEvent 这是一个特定于web的事件,它告诉所有bean已经提供HTTP请求。 |
Spring的事件处理是单线程的,所以如果一个事件被发布,直到并且除非所有的接收者都得到这个消息,这个进程就会被阻塞,流程将不会继续。因此,如果要使用事件处理,应在设计应用程序时小心谨慎。
Listening上下文事件
要监听上下文事件,bean应该实现只有一个方法onApplicationEvent()的ApplicationListener接口。因此,让我们编写一个示例,了解事件是如何传播的,以及如何让代码根据特定事件执行所需的任务。
让我们有一个可用的Eclipse IDE,并采取以下步骤创建一个Spring应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 在com.tutorialspoint包下创建Java类HelloWorld,CStartEventHandler,CStopEventHandler和MainApp。 |
4 | 在src文件夹下创建Beans配置文件Beans.xml。 |
5 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
以下是CStartEventHandler.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextStartedEvent; public class CStartEventHandler implements ApplicationListener<ContextStartedEvent>{ public void onApplicationEvent(ContextStartedEvent event) { System.out.println("ContextStartedEvent Received"); } }
以下是CStopEventHandler.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextStoppedEvent; public class CStopEventHandler implements ApplicationListener<ContextStoppedEvent>{ public void onApplicationEvent(ContextStoppedEvent event) { System.out.println("ContextStoppedEvent Received"); } }
以下是MainApp.java文件的内容
package com.tutorialspoint; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); // Let us raise a start event. context.start(); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); // Let us raise a stop event. context.stop(); } }
以下是配置文件Beans.xml
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"> <property name = "message" value = "Hello World!"/> </bean> <bean id = "cStartEventHandler" class = "com.tutorialspoint.CStartEventHandler"/> <bean id = "cStopEventHandler" class = "com.tutorialspoint.CStopEventHandler"/> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
ContextStartedEvent Received Your Message : Hello World! ContextStoppedEvent Received
如果你愿意,你可以发布自己的自定义事件,然后你可以捕获相同的事件来对这些自定义事件采取任何行动。如果您有兴趣编写自己的自定义事件,则可以在Spring中查看自定义事件。
18 自定义事件
编写和发布自己的自定义事件需要采取多个步骤。按照本章给出的说明编写,发布和处理自定义Spring事件。
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。所有的类都将在这个包下创建。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 通过扩展ApplicationEvent创建一个事件类CustomEvent。这个类必须定义一个默认的构造函数,它应该从ApplicationEvent类继承构造函数。 |
4 | 一旦你的事件类被定义,你可以从任何类发布它,让我们说EventClassPublisher实现ApplicationEventPublisherAware。您还需要在XML配置文件中将此类声明为一个bean,以便容器可以将该bean标识为事件发布者,因为它实现了ApplicationEventPublisherAware接口。 |
5 | 发布的事件可以在类中处理,让我们说EventClassHandler实现ApplicationListener接口并实现自定义事件的onApplicationEvent方法。 |
6 | 在src文件夹下创建bean配置文件Beans.xml以及将作为Spring应用程序工作的MainApp类。 |
7 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是CustomEvent.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationEvent; public class CustomEvent extends ApplicationEvent{ public CustomEvent(Object source) { super(source); } public String toString(){ return "My Custom Event"; } }
以下是CustomEventPublisher.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; public class CustomEventPublisher implements ApplicationEventPublisherAware { private ApplicationEventPublisher publisher; public void setApplicationEventPublisher (ApplicationEventPublisher publisher) { this.publisher = publisher; } public void publish() { CustomEvent ce = new CustomEvent(this); publisher.publishEvent(ce); } }
以下是CustomEventHandler.java文件的内容
package com.tutorialspoint; import org.springframework.context.ApplicationListener; public class CustomEventHandler implements ApplicationListener<CustomEvent> { public void onApplicationEvent(CustomEvent event) { System.out.println(event.toString()); } }
以下是MainApp.java文件的内容
package com.tutorialspoint; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainApp { public static void main(String[] args) { ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); CustomEventPublisher cvp = (CustomEventPublisher) context.getBean("customEventPublisher"); cvp.publish(); cvp.publish(); } }
以下是配置文件Beans.xml
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "customEventHandler" class = "com.tutorialspoint.CustomEventHandler"/> <bean id = "customEventPublisher" class = "com.tutorialspoint.CustomEventPublisher"/> </beans>
一旦完成创建源和配置文件,让我们运行该应用程序。如果你的应用程序一切正常,它会打印下面的消息 -
y Custom Event y Custom Event
19 AOP与Spring框架
面向方面编程(AOP)框架是Spring框架的关键组件之一。面向方面编程需要将程序逻辑分解为称为所谓关注的不同部分。跨越应用程序多个点的功能称为横切关注点,这些横切关注点在概念上与应用程序的业务逻辑分离。有很多常见的很好的例子,例如日志记录,审计,声明式交易,安全性,缓存等等。
OOP中模块化的关键单元是类,而在AOP中,模块化的单元是方面。依赖注入可帮助您将应用程序对象与其他对象解耦,而AOP可帮助您将交叉关注与其影响的对象分离。AOP就像Perl,.NET,Java等编程语言中的触发器。
Spring AOP模块提供拦截器来拦截应用程序。例如,执行方法时,可以在方法执行之前或之后添加额外的功能。
AOP术语
在我们开始使用AOP之前,让我们熟悉AOP的概念和术语。这些术语并非特定于Spring,而是与AOP相关。
条款和说明 | |
---|---|
1 | Aspect 这是一个模块,它有一组提供交叉需求的API。例如,日志记录模块将被称为AOP方面。根据需求,应用程序可以有任何数量的方面。 |
2 | Join point 这代表了您的应用程序中可以插入AOP方面的一个点。您也可以说,它是应用程序中使用Spring AOP框架进行操作的实际位置。 |
3 | Advice 这是在方法执行之前或之后执行的实际操作。这是Spring AOP框架在执行程序期间调用的一段代码。 |
4 | Pointcut 这是一组需要执行建议的一个或多个连接点。您可以使用表达式或模式指定切入点,如我们将在AOP示例中看到的那样。 |
5 | Introduction 介绍允许您向现有类添加新的方法或属性。 |
6 | Target object 目标被一个或多个方面提供建议。该对象将始终是代理对象,也称为建议对象。 |
7 | Weaving 编织是将方面与其他应用程序类型或对象链接以创建建议对象的过程。这可以在编译时,加载时或运行时完成。 |
Advice类型
Spring方面可以使用以下提到的五种建议 -
Sr.No | 建议和说明 |
---|---|
1 | before 在方法执行之前运行建议。 |
2 | after 无论结果如何,在方法执行后运行建议。 |
3 | after-returning 仅在方法成功完成时才在方法执行后运行通知。 |
4 | around 仅当方法通过抛出异常退出时才在方法执行后运行通知。 |
5 | 周围 在调用建议的方法之前和之后运行建议。 |
用户自定义Aspects的实现
Spring支持@AspectJ注释风格方法和基于模式的方法来实现自定义方面。以下部分详细解释了这两种方法。
Sr.No | 方法和说明 |
---|---|
1 | 基于XML模式 方面是使用常规类和基于XML的配置来实现的。 |
2 | @AspectJ为基础 @AspectJ引用一种将方面声明为Java 5注释中标注的常规Java类的样式。 |
20 JDBC框架概述
当使用普通的旧JDBC处理数据库时,编写不必要的代码来处理异常,打开和关闭数据库连接等操作变得很麻烦。但是,Spring JDBC Framework负责打开连接的所有低级细节,准备并执行SQL语句,处理异常,处理事务并最终关闭连接。
因此,您只需定义连接参数并指定要执行的SQL语句,并在从数据库获取数据时为每次迭代执行所需的工作。
Spring JDBC提供了几种方法和相应的不同类来与数据库进行接口。我将采用使用框架的JdbcTemplate类的经典和最流行的方法。这是管理所有数据库通信和异常处理的中心框架类。
JdbcTemplate类
JDBC模板类执行SQL查询,更新语句,存储过程调用,对ResultSets执行迭代,并提取返回的参数值。它还捕获JDBC异常并将它们转换为org.springframework.dao包中定义的通用,更具信息性的异常层次结构。
一旦配置了JdbcTemplate类的实例就是线程安全的。因此,您可以配置JdbcTemplate的单个实例,然后将此共享参考安全地注入到多个DAO中。
使用JDBC Template类时的一个常见做法是在您的Spring配置文件中配置一个DataSource,然后将该共享DataSource bean依赖注入到您的DAO类中,并且在DataSource的setter中创建JdbcTemplate。
配置数据源
让我们在我们的数据库TEST中创建一个数据库表Student。我们假设您正在使用MySQL数据库,如果您使用任何其他数据库,则可以相应地更改您的DDL和SQL查询。
CREATE TABLE Student( ID INT NOT NULL AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, AGE INT NOT NULL, PRIMARY KEY (ID) );
现在我们需要为JDBC模板提供一个数据源,以便它可以自行配置以获取数据库访问权限。您可以使用一段代码在XML文件中配置DataSource,如下面的代码片段所示 -
<bean id = "dataSource" class = "org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name = "driverClassName" value = "com.mysql.jdbc.Driver"/> <property name = "url" value = "jdbc:mysql://localhost:3306/TEST"/> <property name = "username" value = "root"/> <property name = "password" value = "password"/> </bean>
数据访问对象(DAO)
DAO代表数据访问对象,通常用于数据库交互。DAO的存在是为了向数据库读取和写入数据提供一种手段,并且他们应该通过一个接口公开这个功能,应用程序的其余部分将访问它们。
Spring中的DAO支持以一致的方式轻松处理JDBC,Hibernate,JPA或JDO等数据访问技术。
执行SQL语句
让我们看看如何使用SQL和JDBC模板对象对数据库表执行CRUD(创建,读取,更新和删除)操作。
查询int
String SQL = "select count(*) from Student"; int rowCount = jdbcTemplateObject.queryForInt( SQL );
查询long
String SQL = "select count(*) from Student"; long rowCount = jdbcTemplateObject.queryForLong( SQL );
使用绑定变量的简单查询
String SQL = "select age from Student where id = ?"; int age = jdbcTemplateObject.queryForInt(SQL, new Object[]{10});
查询字符串
String SQL = "select name from Student where id = ?"; String name = jdbcTemplateObject.queryForObject(SQL, new Object[]{10}, String.class);
查询并返回一个对象
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; } }
查询和返回多个对象
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; } }
在表格中插入一行
String SQL = "insert into Student (name, age) values (?, ?)"; jdbcTemplateObject.update( SQL, new Object[]{"Zara", 11} );
将行更新到表中
String SQL = "update Student set name = ? where id = ?"; jdbcTemplateObject.update( SQL, new Object[]{"Zara", 10} );
从表中删除一行
String SQL = "delete Student where id = ?"; jdbcTemplateObject.update( SQL, new Object[]{20} );
执行DDL语句
您可以使用jdbcTemplate中的execute(..)方法来执行任何SQL语句或DDL语句。以下是使用CREATE语句创建表的示例 -
String SQL = "CREATE TABLE Student( " + "ID INT NOT NULL AUTO_INCREMENT, " + "NAME VARCHAR(20) NOT NULL, " + "AGE INT NOT NULL, " + "PRIMARY KEY (ID));" jdbcTemplateObject.execute( SQL );
Spring JDBC框架示例
基于上述概念,让我们来检查几个重要的例子,它们将帮助您理解Spring中JDBC框架的用法 -
Sr.No. | 示例和说明 |
---|---|
1 | Spring JDBC示例 这个例子将解释如何编写一个简单的基于JDBC的Spring应用程序。 |
2 | SQL存储过程在Spring中 学习如何在Spring中使用JDBC时调用SQL存储过程。 |
21 事务管理
数据库事务是一系列被视为单个工作单元的操作。这些行动要么完全完成,要么完全不起作用。事务管理是确保数据完整性和一致性的面向RDBMS的企业应用程序的重要组成部分。交易的概念可以用以下四个关键属性来描述:ACID -
原子性 - 交易应被视为一个单一的操作单位,这意味着整个操作顺序是成功还是不成功。
一致性 - 表示数据库的参照完整性,表格中的唯一主键等的一致性。
隔离 - 同一时间同一数据集可能会有许多事务处理。每项交易应与其他人隔离,以防止数据损坏。
耐久性 - 交易完成后,此交易的结果必须永久保存,并且由于系统故障无法从数据库中删除。
真正的RDBMS数据库系统将保证每个事务的所有四个属性。使用SQL发布到数据库的事务的简单视图如下所示 -
使用begin transaction命令开始交易。
使用SQL查询执行各种删除,更新或插入操作。
如果所有操作都成功,则执行提交,否则回滚所有操作。
Spring框架在不同的底层事务管理API之上提供了一个抽象层。Spring的事务支持旨在通过向POJO添加事务功能来提供EJB事务的替代方案。Spring支持编程式和声明式事务管理。EJB需要一个应用服务器,但是Spring事务管理可以在不需要应用服务器的情况下实现。
Local与Global事务
本地事务特定于单个事务资源,如JDBC连接,而全局事务可以跨越多个事务资源,如分布式系统中的事务。
本地事务管理在集中式计算环境中非常有用,其中应用程序组件和资源位于单个站点,而事务管理仅涉及在单台计算机上运行的本地数据管理器。本地交易更容易实施。
在所有资源分布在多个系统中的分布式计算环境中,全局事务管理是必需的。在这种情况下,交易管理需要在当地和全球层面进行。分布式或全局事务跨多个系统执行,其执行需要全局事务管理系统与所有相关系统的所有本地数据管理器之间的协调。
程序化与声明式
Spring支持两种类型的事务管理 -
声明式事务管理优于程序式事务管理,虽然它比程序化事务管理更不灵活,它允许您通过代码控制事务。但作为一种横切关注点,声明式事务管理可以用AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。
Spring Transaction Abstractions
Spring事务抽象的关键是由org.springframework.transaction.PlatformTransactionManager接口定义的,如下所示 -
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition); throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
Sr.No | 方法和描述 |
---|---|
1 | TransactionStatus getTransaction(TransactionDefinition definition) 根据指定的传播行为,此方法返回当前活动的事务或创建一个新事务。 |
2 | void commit(TransactionStatus status) 该方法针对其状态提交给定的事务。 |
3 | void rollback(TransactionStatus status) 此方法执行给定事务的回滚。 |
该TransactionDefinition的是Spring中的事务支持的核心接口,并将其定义如下-
public interface TransactionDefinition { int getPropagationBehavior(); int getIsolationLevel(); String getName(); int getTimeout(); boolean isReadOnly(); }
Sr.No | 方法和描述 |
---|---|
1 | int getPropagationBehavior() 此方法返回传播行为。Spring提供了EJB CMT熟悉的所有事务传播选项。 |
2 | int getIsolationLevel() 此方法返回此交易与其他交易的工作隔离的程度。 |
3 | String getName() 此方法返回此事务的名称。 |
4 | int getTimeout() 此方法返回事务必须完成的时间,以秒为单位。 |
5 | boolean isReadOnly() 此方法返回事务是否为只读。 |
以下是隔离级别的可能值 -
Sr.No | 隔离和说明 |
---|---|
1 | TransactionDefinition.ISOLATION_DEFAULT 这是默认的隔离级别。 |
2 | TransactionDefinition.ISOLATION_READ_COMMITTED 指示防止脏读; 不可重复读取和幻像读取可能发生。 |
3 | TransactionDefinition.ISOLATION_READ_UNCOMMITTED 表示可能发生脏读,不可重复读和幻读。 |
4 | TransactionDefinition.ISOLATION_REPEATABLE_READ 指示防止脏读和不可重复读取; 幻像读取可能会发生。 |
5 | TransactionDefinition.ISOLATION_SERIALIZABLE 表示禁止脏读,不可重复读取和幻像读取。 |
以下是传播类型的可能值 -
Sr.No. | 传播和说明 |
---|---|
1 | TransactionDefinition.PROPAGATION_MANDATORY 支持当前交易; 如果没有当前事务存在,则引发异常。 |
2 | TransactionDefinition.PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行。 |
3 | TransactionDefinition.PROPAGATION_NEVER 不支持当前交易; 如果当前事务存在,则引发异常。 |
4 | TransactionDefinition.PROPAGATION_NOT_SUPPORTED 不支持当前交易; 而是始终以非交易方式执行。 |
5 | TransactionDefinition.PROPAGATION_REQUIRED 支持当前交易; 如果不存在,则创建一个新的。 |
6 | TransactionDefinition.PROPAGATION_REQUIRES_NEW 创建一个新的交易,暂停当前的交易(如果存在)。 |
7 | TransactionDefinition.PROPAGATION_SUPPORTS 支持当前交易; 如果不存在,则以非事务方式执行。 |
8 | TransactionDefinition.TIMEOUT_DEFAULT 使用基础事务系统的默认超时,如果超时不受支持,则使用默认超时。 |
该的TransactionStatus接口提供了一种简单的方式为交易代码,以控制事务执行和查询事务状态。
public interface TransactionStatus extends SavepointManager { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); boolean isCompleted(); }
Sr.No. | 方法和描述 |
---|---|
1 | boolean hasSavepoint() 此方法返回此事务是否内部携带保存点,即,是否已基于保存点创建为嵌套事务。 |
2 | boolean isCompleted() 此方法返回此事务是否已完成,即它是否已提交或回滚。 |
3 | boolean isNewTransaction() 如果当前交易是新的,则此方法返回true。 |
4 | boolean isRollbackOnly() 此方法返回事务是否已标记为仅回滚。 |
5 | void setRollbackOnly() 此方法将事务设置为仅回滚。 |
22 MVC框架
Spring Web MVC框架提供了模型 - 视图 - 控制器(MVC)体系结构和可用于开发灵活和松散耦合的Web应用程序的组件。MVC模式导致分离应用程序的不同方面(输入逻辑,业务逻辑和UI逻辑),同时提供这些元素之间的松散耦合。
该模型封装了应用程序数据,通常它们将由POJO组成。
该视图负责呈现模型数据,并在总体上产生HTML输出,客户端的浏览器可以解释。
该控制器负责处理用户请求,并且建立一个合适的模型,并将其传递到用于呈现该视图。
DispatcherServlet
Spring Web模型 - 视图 - 控制器(MVC)框架是围绕DispatcherServlet设计的,它处理所有HTTP请求和响应。Spring Web MVC DispatcherServlet的请求处理工作流程如下图所示 -
以下是与传入的DispatcherServlet HTTP请求相对应的事件序列-
在接收到HTTP请求后,DispatcherServlet会查询HandlerMapping 以调用相应的Controller。
该控制器接受请求,并调用基于所使用GET或POST方法相应的服务的方法。服务方法将根据定义的业务逻辑设置模型数据,并将视图名称返回给DispatcherServlet。
所述的DispatcherServlet将帮助从的ViewResolver到拾取该请求的已定义视图。
View完成后,DispatcherServlet将模型数据传递给最终在浏览器中呈现的视图。
上述所有组件,即HandlerMapping,Controller和ViewResolver都是WebApplicationContext的一部分,它是普通ApplicationContext的扩展,并带有Web应用程序所需的一些额外功能。
所需的配置
您需要映射您希望DispatcherServlet处理的请求,方法是使用web.xml文件中的URL映射。以下是显示HelloWeb DispatcherServlet示例的声明和映射的示例 -
<web-app id = "WebApp_ID" version = "2.4" xmlns = "http://java.sun.com/xml/ns/j2ee" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring MVC Application</display-name> <servlet> <servlet-name>HelloWeb</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>HelloWeb</servlet-name> <url-pattern>*.jsp</url-pattern> </servlet-mapping> </web-app>
在web.xml中的文件将被保存在你的Web应用程序的WebContent / WEB-INF目录下。在初始化HelloWeb DispatcherServlet时,框架将尝试从位于应用程序的WebContent / WEB-INF 目录中的名为[servlet-name] -servlet.xml的文件加载应用程序上下文。在这种情况下,我们的文件将是HelloWebservlet.xml。
接下来,<servlet-mapping>标签指示哪些URL将由哪个DispatcherServlet处理。这里所有以.jsp结尾的HTTP请求都将由HelloWeb DispatcherServlet 处理。
如果您不想使用缺省文件名作为[servlet-name] -servlet.xml和缺省位置为WebContent / WEB-INF,则可以通过在web.xml文件中添加servlet侦听器ContextLoaderListener来自定义此文件名和位置如下 -
<web-app...> <!-------- DispatcherServlet definition goes here-----> .... <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/HelloWeb-servlet.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> </web-app>
现在,让我们检查放置在Web应用程序的WebContent / WEB-INF目录中的HelloWeb-servlet.xml文件的必需配置-
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:context = "http://www.springframework.org/schema/context" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package = "com.tutorialspoint" /> <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name = "prefix" value = "/WEB-INF/jsp/" /> <property name = "suffix" value = ".jsp" /> </bean> </beans>
以下是关于HelloWeb-servlet.xml文件的要点-
在[servlet的名称] -servlet.xml后缀的文件将被用来创建定义的豆类,覆盖在全球范围内的名字相同的Bean的定义。
所述<上下文:组分扫描...>标签将使用以激活弹簧MVC注释扫描功能,其允许使用像@Controller和@RequestMapping等注解
该 InternalResourceViewResolver这个将定义解析视图名称规则。按照上面定义的规则,名为hello的逻辑视图被委托给位于/WEB-INF/jsp/hello.jsp的视图实现。
以下部分将向您展示如何创建您的实际组件,即Controller,Model和View。
定义一个控制器
DispatcherServlet将请求委托给控制器以执行特定于其的功能。该@Controller注解表明特定类供应控制器的作用。的@RequestMapping注解用于将URL映射到要么整个类或特定处理程序方法。
@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping(method = RequestMethod.GET) public String printHello(ModelMap model) { model.addAttribute("message", "Hello Spring MVC Framework!"); return "hello"; } }
该@Controller注解类定义为Spring MVC的控制器。在这里,@ RequestMapping的第一次使用表明这个控制器上的所有处理方法都是相对于/ hello路径的。下一个注释@RequestMapping(method = RequestMethod.GET)用于声明printHello()方法作为处理HTTP GET请求的控制器的默认服务方法。您可以定义另一种方法来处理同一个URL上的任何POST请求。
您可以用另一种形式编写上述控制器,您可以在@RequestMapping中添加其他属性, 如下所示 -
@Controller public class HelloController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public String printHello(ModelMap model) { model.addAttribute("message", "Hello Spring MVC Framework!"); return "hello"; } }
所述值属性表示该处理程序方法被映射的URL和方法属性定义了服务的方法来处理HTTP GET请求。关于以上定义的控制器,需要注意以下几点:
您将在服务方法内定义所需的业务逻辑。您可以根据需要调用此方法中的另一个方法。
根据定义的业务逻辑,您将在此方法内创建一个模型。您可以使用setter不同的模型属性,这些属性将被视图访问以呈现最终结果。本示例创建一个模型,其属性为“消息”。
定义的服务方法可以返回一个String,其中包含要用于呈现模型的视图的名称。本例返回“hello”作为逻辑视图名称。
创建JSP视图
Spring MVC为不同的表示技术支持多种类型的视图。这些包括--JSP,HTML,PDF,Excel工作表,XML,Velocity模板,XSLT,JSON,Atom和RSS提要,JasperReports等。但最常用的是我们使用JSTL编写的JSP模板。
让我们在/WEB-INF/hello/hello.jsp中编写一个简单的hello视图 -
<html> <head> <title>Hello Spring MVC</title> </head> <body> <h2>${message}</h2> </body> </html>
这里$ {message}是我们在Controller中设置的属性。您可以在视图中显示多个属性。
Spring Web MVC框架示例
基于上述概念,让我们检查几个重要的例子,它们将帮助您构建Spring Web应用程序 -
Sr.No. | 示例和说明 |
---|---|
1 | Spring MVC Hello World示例 这个例子将解释如何编写一个简单的Spring Web Hello World应用程序。 |
2 | Spring MVC表单处理示例 本例将解释如何使用HTML表单编写Spring Web应用程序将数据提交给控制器并显示处理后的结果。 |
3 | Spring页面重定向示例 学习如何在Spring MVC框架中使用页面重定向功能。 |
4 | Spring静态页面示例 学习如何在Spring MVC框架中访问静态页面以及动态页面。 |
5 | Spring异常处理示例 学习如何处理Spring MVC框架中的异常。 |
23 使用Log4J进行日志记录
这是Spring应用程序中非常易于使用的Log4J功能。下面的例子将带您通过简单的步骤来解释Log4J和Spring之间的简单集成。
我们假设你已经在你的机器上安装了log4J。如果你没有它,那么你可以从https://logging.apache.org/下载它,并简单地在任何文件夹中提取压缩文件。我们将在我们的项目中只使用log4j-xyzjar。
接下来,让我们有一个可用的Eclipse IDE,并采用以下步骤使用Spring Web Framework开发基于动态表单的Web应用程序 -
描述 | |
---|---|
1 | 创建一个名称为SpringExample的项目,并在创建的项目的src文件夹下创建一个com.tutorialspoint包。 |
2 | 按照Spring Hello World Example章节的介绍,使用Add External JARs选项添加所需的Spring库。 |
3 | 使用添加外部JAR在您的项目中添加log4j库log4j-xyzjar。 |
4 | 在com.tutorialspoint包下创建Java类HelloWorld和MainApp。 |
5 | 在src文件夹下创建Beans配置文件Beans.xml。 |
6 | 在src文件夹下创建log4J配置文件log4j.properties。 |
7 | 最后一步是创建所有Java文件和Bean配置文件的内容并按照下面的说明运行应用程序。 |
这里是HelloWorld.java文件的内容
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage() { System.out.println("Your Message : " + message); } }
以下是第二个文件MainApp.java的内容
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.apache.log4j.Logger; public class MainApp { static Logger log = Logger.getLogger(MainApp.class.getName()); public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); log.info("Going to create HelloWord Obj"); HelloWorld obj = (HelloWorld) context.getBean("helloWorld"); obj.getMessage(); log.info("Exiting the program"); } }
您可以使用与生成信息消息类似的方式生成调试和错误消息。现在让我们看看Beans.xml文件的内容
<?xml version = "1.0" encoding = "UTF-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"> <property name = "message" value = "Hello World!"/> </bean> </beans>
以下是log4j.properties的内容,它定义了Log4J生成日志消息所需的标准规则
# Define the root logger with appender file log4j.rootLogger = DEBUG, FILE # Define the file appender log4j.appender.FILE=org.apache.log4j.FileAppender # Set the name of the file log4j.appender.FILE.File=C:\\log.out # Set the immediate flush to true (default) log4j.appender.FILE.ImmediateFlush=true # Set the threshold to debug mode log4j.appender.FILE.Threshold=debug # Set the append to false, overwrite log4j.appender.FILE.Append=false # Define the layout for file appender log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout.conversionPattern=%m%n
一旦完成创建源和bean配置文件,让我们运行该应用程序。如果您的应用程序一切正常,这将在Eclipse控制台中显示以下消息 -
Your Message : Hello World!
如果你检查你的C:\\驱动器,那么你应该找到你的日志文件log.out与各种日志消息,如下所示 -
<!-- initialization log messages --> Going to create HelloWord Obj Returning cached instance of singleton bean 'helloWorld' Exiting the program
Jakarta Commons Logging(JCL)API
或者,您可以使用Jakarta Commons Logging(JCL) API在Spring应用程序中生成日志。JCL可以从https://jakarta.apache.org/commons/logging/下载。我们在技术上需要的唯一文件是commons-logging-xyzjar文件,它需要像上面例子中的log4j-xyzjar一样放置在你的类路径中。
要使用日志记录功能,您需要一个org.apache.commons.logging.Log对象,然后可以根据您的需求调用以下方法之一 -
-
- fatal(Object message)
- error(Object message)
- warn(Object message)
- info(Object message)
- debug(Object message)
- trace(Object message)
以下是使用JCL API的MainApp.java的替换
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-xyzjar文件。
现在,在上面的例子中保持其他配置和内容不变,如果您编译并运行您的应用程序,您将得到与使用Log4J API相似的结果。