0
点赞
收藏
分享

微信扫一扫

spring入门

JakietYu 2022-04-08 阅读 59
spring

spring

一, spring的基本应用

1. spring概述

1.1 什么是spring

spring是一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,它以IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为内核.使用基本的JavaBean来完成以前只可能由EJB(Enterprise Java Beans,java企业Bean)完成的工作,取代了EJB的臃肿,低效的开发模式.

1.2 spring的框架优点

  • 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
  • 控制反转:IOC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架。
  • 依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用 setXX 方法去设置,而是通过配置赋值。
  • 面向切面编程:Aspect Oriented Programming——AOP
  • 容器:Spring 是一个容器,因为它包含并且管理应用对象的生命周期
  • 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
  • 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring 自身也提供了表现层的 SpringMVC 和持久层的 Spring JDBC)

1.3 Spring 框架具有以下几个特点:

1)方便解耦,简化开发

Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

2)方便集成各种优秀框架

Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

3)降低 Java EE API 的使用难度

Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

4)方便程序的测试

Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。

5)AOP 编程的支持

Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

6)声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无须手动编程。

1.4 spring的体系结构

Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。下面的部分对在 Spring 框架中所有可用的模块给出了详细的介绍。

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。

Spring 体系结构

核心容器

核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

  • spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
  • context 模块建立在由 corebeans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。spring-context-support 提供了对第三方集成到 Spring 上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。
  • spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

它们的完整依赖关系如下图所示:

Spring 体系结构

数据访问/集成

数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
  • ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
  • OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)

Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  • Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
  • Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
  • Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

Test模块

Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。

其他

还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  • AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

2. spring的核心容器

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans,我们将在下一章中进行讨论。

通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。下图是 Spring 如何工作的高级视图。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。

Spring IoC 容器

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

序号容器 & 描述
1Spring BeanFactory 容器它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。
2Spring ApplicationContext 容器该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。

2.1 Spring的BeanFactory容器

这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactory中被定义。BeanFactory 和相关的接口,比如BeanFactoryAware、DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

步骤描述
1创建一个名为 SpringExample 的工程并在 src 文件夹下新建一个名为 com.tutorialspoint 文件夹。
2点击右键,选择 Add External JARs 选项,导入 Spring 的库文件,正如我们在 Spring Hello World Example 章节中提到的导入方式。
3com.tutorialspoint 文件夹下创建 HelloWorld.javaMainApp.java 两个类文件。
4src 文件夹下创建 Bean 的配置文件 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.beans.factory.InitializingBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class MainApp {
   public static void main(String[] args) {
      XmlBeanFactory factory = new XmlBeanFactory
                             (new ClassPathResource("Beans.xml"));
      HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");
      obj.getMessage();
   }
}

在主程序当中,我们需要注意以下两点:

  • 第一步利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource() API 去加载在路径 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API 负责创建并初始化所有的对象,即在配置文件中提到的 bean。
  • 第二步利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象,该对象最后可以用于实际的对象。一旦得到这个对象,你就可以利用这个对象来调用任何方法。

下面是配置文件 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>

如果你已经完成上面的内容,接下来,让我们运行这个应用程序。如果程序没有错误,你将从控制台看到以下信息:

Your Message : Hello World!

2.2 Spring ApplicationContext 容器

Application Context 是 BeanFactory 的子接口,也被称为 Spring 上下文。

Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

我们已经在 Spring Hello World Example章节中看到过 ClassPathXmlApplicationContext 容器,并且,在基于 spring 的 web 应用程序这个独立的章节中,我们讨论了很多关于 WebXmlApplicationContext。所以,接下来,让我们看一个关于 FileSystemXmlApplicationContext 的例子。

例子:

假设我们已经安装 Eclipse IDE,按照下面的步骤,我们可以创建一个 Spring 应用程序。

步骤描述
1创建一个名为 SpringExample 的工程, 在 src 下新建一个名为 com.tutorialspoint 的文件夹src
2点击右键,选择 Add External JARs 选项,导入 Spring 的库文件,正如我们在 Spring Hello World Example 章节中提到的导入方式。
3在 com.tutorialspoint 文件夹下创建 HelloWorld.java 和 MainApp.java 两个类文件。
4文件夹下创建 Bean 的配置文件 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.FileSystemXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext
            ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

在主程序当中,我们需要注意以下两点:

  • 第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext API 去生成工厂 bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean 配置文件中的 bean。
  • 第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

下面是配置文件 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>

如果你已经完成上面的内容,接下来,让我们运行这个应用程序。如果程序没有错误,你将从控制台看到以下信息:

Your Message : Hello World!

二,spring中的Bean

1. Bean 定义

被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的,例如,已经在先前章节看到的,在 XML 的表单中的 定义。

bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:

  • 如何创建一个 bean
  • bean 的生命周期的详细信息
  • bean 的依赖关系

上述所有的配置元数据转换成一组构成每个 bean 定义的下列属性。

属性描述
class这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
name这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
scope这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。
constructor-arg它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
properties它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
autowiring mode它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
lazy-initialization mode延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
initialization 方法在 bean 的所有必需的属性被容器设置之后,调用回调方法。它将会在 bean 的生命周期章节中进行讨论。
destruction 方法当包含该 bean 的容器被销毁时,使用回调方法。它将会在 bean 的生命周期章节中进行讨论。

Bean 与 Spring 容器的关系

下图表达了Bean 与 Spring 容器之间的关系:

Spring Bean

2. Spring 配置元数据

Spring IoC 容器完全由实际编写的配置元数据的格式解耦。有下面三个重要的方法把配置元数据提供给 Spring 容器:

  • 基于 XML 的配置文件
  • 基于注解的配置
  • 基于 Java 的配置

提示:对于基于 XML 的配置,Spring 2.0 以后使用 Schema 的格式,使得不同类型的配置拥有了自己的命名空间,使配置文件更具扩展性。

你已经看到了如何把基于 XML 的配置元数据提供给容器,但是让我们看看另一个基于 XML 配置文件的例子,这个配置文件中有不同的 bean 定义,包括延迟初始化,初始化方法和销毁方法的:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">   <!-- A simple bean definition -->   <bean id="..." class="...">       <!-- collaborators and configuration for this bean go here -->   </bean>   <!-- A bean definition with lazy init set on -->   <bean id="..." class="..." lazy-init="true">       <!-- collaborators and configuration for this bean go here -->   </bean>   <!-- A bean definition with initialization method -->   <bean id="..." class="..." init-method="...">       <!-- collaborators and configuration for this bean go here -->   </bean>   <!-- A bean definition with destruction method -->   <bean id="..." class="..." destroy-method="...">       <!-- collaborators and configuration for this bean go here -->   </bean>   <!-- more bean definitions go here --></beans>

在上述示例中:

①xmlns=“http://www.springframework.org/schema/beans”,默认命名空间:它没有空间名,用于Spring Bean的定义;

②xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”,xsi命名空间:这个命名空间用于为每个文档中命名空间指定相应的Schema样式文件,是标准组织定义的标准命名空间。

3. Spring 依赖注入

Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。

每个基于应用程序的 java 都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。

假设你有一个包含文本编辑器组件的应用程序,并且你想要提供拼写检查。标准代码看起来是这样的:

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

在这里我们所做的就是创建一个 TextEditor 和 SpellChecker 之间的依赖关系。而在控制反转IoC的场景中,我们会这样做:

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 主要有两种变体和下面的两个子章将结合实例涵盖它们:

序号依赖注入类型 & 描述
1Constructor-based dependency injection当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系。
2Setter-based dependency injection基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。

你可以混合这两种方法,基于构造函数和基于 setter 方法的 DI,然而使用有强制性依存关系的构造函数和有可选依赖关系的 sette r是一个好的做法。

代码是 DI 原理的清洗机,当对象与它们的依赖关系被提供时,解耦效果更明显。对象不查找它的依赖关系,也不知道依赖关系的位置或类,而这一切都由 Spring 框架控制的。

3.1 Spring 基于构造函数的依赖注入

当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。

接下来,我们将通过示例来理解 Spring 基于构造函数的依赖注入。

下面的例子显示了一个类 TextEditor,只能用构造函数注入来实现依赖注入。

让我们用 Eclipse IDE 适当地工作,并按照以下步骤创建一个 Spring 应用程序。

步骤描述
1创建一个名为 SpringExample 的项目,并在创建的项目中的 src 文件夹下创建包 com.tutorialspoint
2使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example chapter.
3com.tutorialspoint 包下创建 Java类 TextEditorSpellCheckerMainApp
4src 文件夹下创建 Beans 的配置文件 Beans.xml
5最后一步是创建所有 Java 文件和 Bean 配置文件的内容并按照如下所示的方法运行应用程序。

这是 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.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 的内容,它有基于构造函数注入的配置:

<?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 -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor">      <constructor-arg ref="spellChecker"/>   </bean>   <!-- Definition for spellChecker bean -->   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

当你完成了创建源和 bean 配置文件后,让我们开始运行应用程序。如果你的应用程序运行顺利的话,那么将会输出下述所示消息:

Inside SpellChecker constructor.Inside TextEditor constructor.Inside checkSpelling.

构造函数参数解析:

注释:上面这个例子里,将依赖类 SpellChecker.java注入到TextEditor.java 文件。

如此,便称为依赖注入。

如果存在不止一个参数时,当把参数传递给构造函数时,可能会存在歧义。要解决这个问题,那么构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序就可以了。

考虑下面的类:

package x.y;public class Foo {   public Foo(Bar bar, Baz baz) {      // ...   }}

下述配置文件工作顺利:

<beans>   <bean id="foo" class="x.y.Foo">      <constructor-arg ref="bar"/>      <constructor-arg ref="baz"/>   </bean>   <bean id="bar" class="x.y.Bar"/>   <bean id="baz" class="x.y.Baz"/></beans>

让我们再检查一下我们传递给构造函数不同类型的位置。考虑下面的类:

package x.y;public class Foo {   public Foo(int year, String name) {      // ...   }}

如果你使用 type 属性显式的指定了构造函数参数的类型,容器也可以使用与简单类型匹配的类型。例如:

<beans>   <bean id="exampleBean" class="examples.ExampleBean">      <constructor-arg type="int" value="2001"/>      <constructor-arg type="java.lang.String" value="Zara"/>   </bean></beans>

最后并且也是最好的传递构造函数参数的方式,使用 index 属性来显式的指定构造函数参数的索引。下面是基于索引为 0 的例子,如下所示:

<beans>   <bean id="exampleBean" class="examples.ExampleBean">      <constructor-arg index="0" value="2001"/>      <constructor-arg index="1" value="Zara"/>   </bean></beans>

最后,如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

3.2 Spring 基于设值函数的依赖注入

当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。

下述例子显示了一个类 TextEditor,它只能使用纯粹的基于设值函数的注入来实现依赖注入。

让我们用 Eclipse IDE 适当地工作,并按照以下步骤创建一个 Spring 应用程序。

步骤描述
1创建一个名为 SpringExample 的项目,并在创建的项目中的 src 文件夹下创建包 com.tutorialspoint
2使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example chapter.
3com.tutorialspoint 包下创建 Java类 TextEditorSpellCheckerMainApp
4src 文件夹下创建 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,我们使用 setSpellChecker() 方法,该方法与 Java POJO 类非常相似。让我们创建另一个依赖类文件 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 的内容,该文件有基于设值函数注入的配置:

<?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 -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor">      <property name="spellChecker" ref="spellChecker"/>   </bean>   <!-- Definition for spellChecker bean -->   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

你应该注意定义在基于构造函数注入和基于设值函数注入中的 Beans.xml 文件的区别。唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。

第二个你需要注意的点是,如果你要把一个引用传递给一个对象,那么你需要使用 标签的 ref 属性,而如果你要直接传递一个值,那么你应该使用 value 属性。

当你完成了创建源和 bean 配置文件后,让我们开始运行应用程序。如果你的应用程序运行顺利的话,那么将会输出下述所示消息:

Inside SpellChecker constructor.Inside setSpellChecker.Inside checkSpelling.

使用 p-namespace 实现 XML 配置:

如果你有许多的设值函数方法,那么在 XML 配置文件中使用 p-namespace 是非常方便的。让我们查看一下区别:

以带有 标签的标准 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="john-classic" class="com.example.Person">      <property name="name" value="John Doe"/>      <property name="spouse" ref="jane"/>   </bean>   <bean name="jane" class="com.example.Person">      <property name="name" value="John Doe"/>   </bean></beans>

上述 XML 配置文件可以使用 p-namespace 以一种更简洁的方式重写,如下所示:

<?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:p="http://www.springframework.org/schema/p"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">   <bean id="john-classic" class="com.example.Person"      p:name="John Doe"      p:spouse-ref="jane"/>   </bean>   <bean name="jane" class="com.example.Person"      p:name="John Doe"/>   </bean></beans>

在这里,你不应该区别指定原始值和带有 p-namespace 的对象引用。-ref 部分表明这不是一个直接的值,而是对另一个 bean 的引用。

4. Beans 自动装配

你已经学会如何使用<bean>元素来声明 bean 和通过使用 XML 配置文件中的<constructor-arg><property>元素来注入 。

Spring 容器可以在不使用<constructor-arg><property> 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。

自动装配模式

下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用<bean>元素的 autowire 属性为一个 bean 定义指定自动装配模式。

模式描述
no这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。
byName由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。
byType由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。
constructor类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。
autodetect(3.0版本不支持)Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。

可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。

自动装配的局限性

当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。

限制描述
重写的可能性你可以使用总是重写自动装配的 和 设置来指定依赖关系。
原始数据类型你不能自动装配所谓的简单类型包括基本类型,字符串和类。
混乱的本质自动装配不如显式装配精确,所以如果可能的话尽可能使用显式装配。

4.1 Spring 自动装配 byName

这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

例如,在配置文件中,如果一个 bean 定义设置为自动装配 byName,并且它包含 spellChecker 属性(即,它有一个 setSpellChecker(…) 方法),那么 Spring 就会查找定义名为 spellChecker 的 bean,并且用它来设置这个属性。你仍然可以使用 标签连接其余的属性。下面的例子将说明这个概念。

让我们在恰当的位置使用 Eclipse IDE,然后按照下面的步骤来创建一个 Spring 应用程序:

步骤描述
1创建一个名称为 SpringExample 的项目,并且在已创建的项目的 src 文件夹中创建一个包 com.tutorialspoint
2使用 Add External JARs 选项,添加所需的 Spring 库,在 Spring Hello World Example 章节中已说明。
3com.tutorialspoint 包中创建 Java 类 TextEditorSpellCheckerMainApp
4src 文件夹中创建 Beans 的配置文件 Beans.xml
5最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并运行该应用程序,正如下面解释的一样。

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;public class TextEditor {   private SpellChecker spellChecker;   private String name;   public void setSpellChecker( SpellChecker spellChecker ){      this.spellChecker = spellChecker;   }   public SpellChecker getSpellChecker() {      return spellChecker;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      return name;   }   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 文件:

<?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 -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor">       <property name="spellChecker" ref="spellChecker" />       <property name="name" value="Generic Text Editor" />   </bean>   <!-- Definition for spellChecker bean -->   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

但是,如果你要使用自动装配 “byName”,那么你的 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 textEditor bean -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor"       autowire="byName">      <property name="name" value="Generic Text Editor" />   </bean>   <!-- Definition for spellChecker bean -->   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

一旦你完成了创建源代码和 bean 的配置文件,我们就可以运行该应用程序。如果你的应用程序一切都正常,它将打印下面的消息:

Inside SpellChecker constructor.Inside checkSpelling.

4.2 Spring 自动装配 byType

这种模式由属性类型指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beansautowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。

例如,在配置文件中,如果一个 bean 定义设置为自动装配 byType,并且它包含 SpellChecker 类型的 spellChecker 属性,那么 Spring 就会查找类型为 SpellCheckerbean,并且用它来设置这个属性。你仍然可以使用 <property> 标签连接其余属性。下面的例子将说明这个概念,你会发现和上面的例子没有什么区别,除了 XML 配置文件已经被改变。

让我们在恰当的位置使用Eclipse IDE,然后按照下面的步骤来创建一个 Spring 应用程序:

步骤描述
1创建一个名称为 SpringExample 的项目,并且在已创建的项目的 src 文件夹中创建一个包 com.tutorialspoint
2使用 Add External JARs 选项,添加所需的 Spring 库,在 Spring Hello World Example 章节中已说明。
3com.tutorialspoint 包中创建 JavaTextEditorSpellCheckerMainApp
4src 文件夹中创建 Beans 的配置文件 Beans.xml
5最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并运行该应用程序,正如下面解释的一样。

这里是 TextEditor.java 文件的内容:

package com.tutorialspoint;public class TextEditor {   private SpellChecker spellChecker;   private String name;   public void setSpellChecker( SpellChecker spellChecker ) {      this.spellChecker = spellChecker;   }   public SpellChecker getSpellChecker() {      return spellChecker;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      return name;   }   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 文件:

<?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 -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor">      <property name="spellChecker" ref="spellChecker" />      <property name="name" value="Generic Text Editor" />   </bean>   <!-- Definition for spellChecker bean -->   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

但是,如果你要使用自动装配 “byType”,那么你的 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 textEditor bean -->   <bean id="textEditor" class="com.tutorialspoint.TextEditor"       autowire="byType">      <property name="name" value="Generic Text Editor" />   </bean>   <!-- Definition for spellChecker bean -->   <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">   </bean></beans>

一旦你完成了创建源代码和 bean 的配置文件,我们就可以运行该应用程序。如果你的应用程序一切都正常,它将打印下面的消息:

Inside SpellChecker constructor.Inside checkSpelling.

5. 基于注解的配置

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。

在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。

注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-3.0.xsd">   <context:annotation-config/>   <!-- bean definitions go here --></beans>

一旦 被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。让我们来看看几个重要的注解,并且了解它们是如何工作的:

序号注解 & 描述
1@Required@Required 注解应用于 bean 属性的 setter 方法。
2@Autowired@Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。
3@Qualifier通过指定确切的将被连线的 bean,@Autowired 和 @Qualifier 注解可以用来删除混乱。
4JSR-250 AnnotationsSpring 支持 JSR-250 的基础的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。

使用 Spring 开发时,进行配置主要有两种方式,一是 xml 的方式,二是 java config 的方式。Spring 技术自身也在不断的发展和改变,从当前 Springboot 的火热程度来看,java config 的应用是越来越广泛了,在使用 java config 的过程当中,我们不可避免的会有各种各样的注解打交道,其中,我们使用最多的注解应该就是 @Autowired 注解了。这个注解的功能就是为我们注入一个定义好的 bean。

5.1 @Autowired 注解的作用到底是什么?

@Autowired 这个注解我们经常在使用,现在,我想问的是,它的作用到底是什么呢?

首先,我们从所属范围来看,事实上这个注解是属于 Spring 的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier 等等。因此 @Autowired 注解是一个用于容器 ( container ) 配置的注解。

其次,我们可以直接从字面意思来看,@autowired 注解来源于英文单词 autowire,这个单词的意思是自动装配的意思。自动装配又是什么意思?这个词语本来的意思是指的一些工业上的用机器代替人口,自动将一些需要完成的组装任务,或者别的一些任务完成。而在 Spring 的世界当中,自动装配指的就是使用将 Spring 容器中的 bean 自动的和我们需要这个 bean 的类组装在一起。

5.2 @Autowired 注解用法

在分析这个注解的实现原理之前,我们不妨先来回顾一下 @Autowired 注解的用法。

将 @Autowired 注解应用于构造函数,如以下示例所示

public class MovieRecommender {     private final CustomerPreferenceDao customerPreferenceDao;     @Autowired    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {        this.customerPreferenceDao = customerPreferenceDao;    }     // ...}

将 @Autowired 注解应用于 setter 方法

public class SimpleMovieLister {     private MovieFinder movieFinder;     @Autowired    public void setMovieFinder(MovieFinder movieFinder) {        this.movieFinder = movieFinder;    }     // ...}

将 @Autowired 注解应用于具有任意名称和多个参数的方法

public class MovieRecommender {     private MovieCatalog movieCatalog;     private CustomerPreferenceDao customerPreferenceDao;     @Autowired    public void prepare(MovieCatalog movieCatalog,            CustomerPreferenceDao customerPreferenceDao) {        this.movieCatalog = movieCatalog;        this.customerPreferenceDao = customerPreferenceDao;    }     // ...}

您也可以将 @Autowired 注解应用于字段,或者将其与构造函数混合,如以下示例所示

public class MovieRecommender {     private final CustomerPreferenceDao customerPreferenceDao;     @Autowired    private MovieCatalog movieCatalog;     @Autowired    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {        this.customerPreferenceDao = customerPreferenceDao;    }     // ...}

直接应用于字段是我们使用的最多的一种方式,但是使用构造方法注入从代码层面却是更加好的。除此之外,还有以下不太常见的几种方式

将 @Autowired 注解添加到需要该类型数组的字段或方法,则 Spring 会从 ApplicationContext 中搜寻符合指定类型的所有 bean,如以下示例所示:

public class MovieRecommender {     @Autowired    private MovieCatalog[] movieCatalogs;     // ...}

数组可以,我们可以马上举一反三,那容器也可以吗,答案是肯定的,下面是 set 以及 map 的例子:

public class MovieRecommender {     private Set<MovieCatalog> movieCatalogs;     @Autowired    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {        this.movieCatalogs = movieCatalogs;    }     // ...}public class MovieRecommender {     private Map<String, MovieCatalog> movieCatalogs;     @Autowired    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {        this.movieCatalogs = movieCatalogs;    }     // ...}

以上就是 @Autowired 注解的主要使用方式,经常使用 Spring 的话应该对其中常用的几种不会感到陌生。

三,springAOP

1.Spring 框架的 AOP

Spring 框架的一个关键组件是面向切面的编程(AOP)框架。面向切面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。在软件开发过程中有各种各样的很好的切面的例子,如日志记录、审计、声明式事务、安全性和缓存等。

在 OOP 中,关键单元模块度是类,而在 AOP 中单元模块度是切面。依赖注入帮助你对应用程序对象相互解耦合,AOP 可以帮助你从它们所影响的对象中对横切关注点解耦。AOP 像是编程语言的触发物,如 Perl,.NET,Java 或者其他语言。

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

1.1 AOP 术语

在我们开始使用 AOP 工作之前,让我们熟悉一下 AOP 概念和术语。这些术语并不特定于 Spring,而是与 AOP 有关的。

描述
Aspect一个模块具有一组提供横切需求的 APIs。例如,一个日志模块为了记录日志将被 AOP 方面调用。应用程序可以拥有任意数量的方面,这取决于需求。
Join point在你的应用程序中它代表一个点,你可以在插件 AOP 方面。你也能说,它是在实际的应用程序中,其中一个操作将使用 Spring AOP 框架。
Advice这是实际行动之前或之后执行的方法。这是在程序执行期间通过 Spring AOP 框架实际被调用的代码。
Pointcut这是一组一个或多个连接点,通知应该被执行。你可以使用表达式或模式指定切入点正如我们将在 AOP 的例子中看到的。
Introduction引用允许你添加新方法或属性到现有的类中。
Target object被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。
WeavingWeaving 把方面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。

1.2 通知的类型

Spring 方面可以使用下面提到的五种通知工作:

通知描述
前置通知在一个方法执行之前,执行通知。
后置通知在一个方法执行之后,不考虑其结果,执行通知。
返回后通知在一个方法执行之后,只有在方法成功完成时,才能执行通知。
抛出异常后通知在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知在建议方法调用之前和之后,执行通知。

1.3 实现自定义方面

Spring 支持 @AspectJ annotation style 的方法和基于模式的方法来实现自定义方面。这两种方法已经在下面两个子节进行了详细解释。

方法描述
XML Schema based方面是使用常规类以及基于配置的 XML 来实现的。
@AspectJ based@AspectJ 引用一种声明方面的风格作为带有 Java 5 注释的常规 Java 类注释。

2. Spring 中基于 AOP 的 XML架构

为了在本节的描述中使用 aop 命名空间标签,你需要导入 spring-aop j架构,如下所述:

<?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:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">   <!-- bean definition & AOP specific configuration --></beans>

你还需要在你的应用程序的 CLASSPATH 中使用以下 AspectJ 库文件。这些库文件在一个 AspectJ 装置的 ‘lib’ 目录中是可用的,否则你可以在 Internet 中下载它们。(注:aspectjweaver.jar 已包含其他包)

  • aspectjrt.jar
  • aspectjweaver.jar
  • aspectj.jar
  • aopalliance.jar

2.1 声明一个 aspect

一个 aspect 是使用 元素声明的,支持的 bean 是使用 ref 属性引用的,如下所示:

<aop:config>   <aop:aspect id="myAspect" ref="aBean">   ...   </aop:aspect></aop:config><bean id="aBean" class="...">...</bean>

这里,“aBean” 将被配置和依赖注入,就像前面的章节中你看到的其他的 Spring bean 一样。

2.2 声明一个切入点

一个切入点有助于确定使用不同建议执行的感兴趣的连接点(即方法)。在处理基于配置的 XML 架构时,切入点将会按照如下所示定义:

<aop:config>   <aop:aspect id="myAspect" ref="aBean">   <aop:pointcut id="businessService"      expression="execution(* com.xyz.myapp.service.*.*(..))"/>   ...   </aop:aspect></aop:config><bean id="aBean" class="...">...</bean>

下面的示例定义了一个名为 “businessService” 的切入点,该切入点将与 com.tutorialspoint 包下的 Student 类中的 getName() 方法相匹配:

<aop:config>   <aop:aspect id="myAspect" ref="aBean">   <aop:pointcut id="businessService"      expression="execution(* com.tutorialspoint.Student.getName(..))"/>   ...   </aop:aspect></aop:config><bean id="aBean" class="...">...</bean>

2.3 声明建议

你可以在aop:aspect中使用aop:{通知类型名}元素声明任意五种类型的通知,如下:

<aop:config>   <aop:aspect id="myAspect" ref="aBean">      <aop:pointcut id="businessService"         expression="execution(* com.xyz.myapp.service.*.*(..))"/>      <!-- a before advice definition -->      <aop:before pointcut-ref="businessService"          method="doRequiredTask"/>      <!-- an after advice definition -->      <aop:after pointcut-ref="businessService"          method="doRequiredTask"/>      <!-- an after-returning advice definition -->      <!--The doRequiredTask method must have parameter named retVal -->      <aop:after-returning pointcut-ref="businessService"         returning="retVal"         method="doRequiredTask"/>      <!-- an after-throwing advice definition -->      <!--The doRequiredTask method must have parameter named ex -->      <aop:after-throwing pointcut-ref="businessService"         throwing="ex"         method="doRequiredTask"/>      <!-- an around advice definition -->      <aop:around pointcut-ref="businessService"          method="doRequiredTask"/>   ...   </aop:aspect></aop:config><bean id="aBean" class="...">...</bean>

你可以对不同的建议使用相同的 doRequiredTask 或者不同的方法。这些方法将会作为 aspect 模块的一部分来定义。

2.4 基于 AOP 的 XML 架构的示例

为了理解上面提到的基于 AOP 的 XML 架构的概念,让我们编写一个示例,可以实现几个建议。为了在我们的示例中使用几个建议,让我们使 Eclipse IDE 处于工作状态,然后按照如下步骤创建一个 Spring 应用程序:

步骤描述
1创建一个名为 SpringExample 的项目,并且在所创建项目的 src 文件夹下创建一个名为 com.tutorialspoint 的包。
2使用 Add External JARs 选项添加所需的 Spring 库文件,就如在 Spring Hello World Example 章节中解释的那样。
3在项目中添加 Spring AOP 指定的库文件 aspectjrt.jar, aspectjweaver.jaraspectj.jar
4com.tutorialspoint 包下创建 Java 类 LoggingStudentMainApp
5src 文件夹下创建 Beans 配置文件 Beans.xml
6最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并且按如下解释的那样运行应用程序。

这里是 Logging.java 文件的内容。这实际上是 aspect 模块的一个示例,它定义了在各个点调用的方法。

package com.tutorialspoint;public class Logging {   /**     * This is the method which I would like to execute    * before a selected method execution.    */   public void beforeAdvice(){      System.out.println("Going to setup student profile.");   }   /**     * This is the method which I would like to execute    * after a selected method execution.    */   public void afterAdvice(){      System.out.println("Student profile has been setup.");   }   /**     * This is the method which I would like to execute    * when any method returns.    */   public void afterReturningAdvice(Object retVal){      System.out.println("Returning:" + retVal.toString() );   }   /**    * This is the method which I would like to execute    * if there is an exception raised.    */   public void AfterThrowingAdvice(IllegalArgumentException ex){      System.out.println("There has been an exception: " + ex.toString());      }  }

下面是 Student.java 文件的内容:

package com.tutorialspoint;public class Student {   private Integer age;   private String name;   public void setAge(Integer age) {      this.age = age;   }   public Integer getAge() {      System.out.println("Age : " + age );      return age;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      System.out.println("Name : " + name );      return name;   }     public void printThrowException(){       System.out.println("Exception raised");       throw new IllegalArgumentException();   }}

下面是 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");      Student student = (Student) context.getBean("student");      student.getName();      student.getAge();            student.printThrowException();   }}

下面是配置文件 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"     xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">   <aop:config>      <aop:aspect id="log" ref="logging">         <aop:pointcut id="selectAll"          expression="execution(* com.tutorialspoint.*.*(..))"/>         <aop:before pointcut-ref="selectAll" method="beforeAdvice"/>         <aop:after pointcut-ref="selectAll" method="afterAdvice"/>         <aop:after-returning pointcut-ref="selectAll"                               returning="retVal"                              method="afterReturningAdvice"/>         <aop:after-throwing pointcut-ref="selectAll"                              throwing="ex"                             method="afterThrowingAdvice"/>      </aop:aspect>   </aop:config>   <!-- Definition for student bean -->   <bean id="student" class="com.tutorialspoint.Student">      <property name="name"  value="Zara" />      <property name="age"  value="11"/>         </bean>   <!-- Definition for logging aspect -->   <bean id="logging" class="com.tutorialspoint.Logging"/> </beans>

一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

Going to setup student profile.Name : ZaraStudent profile has been setup.Returning:ZaraGoing to setup student profile.Age : 11Student profile has been setup.Returning:11Going to setup student profile.Exception raisedStudent profile has been setup.There has been an exception: java.lang.IllegalArgumentException.....other exception content

让我们来解释一下上面定义的在 com.tutorialspoint 中 选择所有方法的 。让我们假设一下,你想要在一个特殊的方法之前或者之后执行你的建议,你可以通过替换使用真实类和方法名称的切入点定义中的星号(*)来定义你的切入点来缩短你的执行。

<?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:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">   <aop:config>   <aop:aspect id="log" ref="logging">      <aop:pointcut id="selectAll"       expression="execution(* com.tutorialspoint.Student.getName(..))"/>      <aop:before pointcut-ref="selectAll" method="beforeAdvice"/>      <aop:after pointcut-ref="selectAll" method="afterAdvice"/>   </aop:aspect>   </aop:config>   <!-- Definition for student bean -->   <bean id="student" class="com.tutorialspoint.Student">      <property name="name"  value="Zara" />      <property name="age"  value="11"/>         </bean>   <!-- Definition for logging aspect -->   <bean id="logging" class="com.tutorialspoint.Logging"/> </beans>

如果你想要执行通过这些更改之后的示例应用程序,这将会输出以下消息:

Going to setup student profile.Name : ZaraStudent profile has been setup.Age : 11Exception raised.....other exception content

3. Spring 中基于 AOP 的 @AspectJ

@AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格。通过在你的基于架构的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的。

<aop:aspectj-autoproxy/>

你还需要在你的应用程序的 CLASSPATH 中使用以下 AspectJ 库文件。这些库文件在一个 AspectJ 装置的 ‘lib’ 目录中是可用的,如果没有,你可以在 Internet 中下载它们。

  • aspectjrt.jar
  • aspectjweaver.jar
  • aspectj.jar
  • aopalliance.jar

3.1声明一个 aspect

Aspects 类和其他任何正常的 bean 一样,除了它们将会用 @AspectJ 注释之外,它和其他类一样可能有方法和字段,如下所示:

package org.xyz;import org.aspectj.lang.annotation.Aspect;@Aspectpublic class AspectModule {}

它们将在 XML 中按照如下进行配置,就和其他任何 bean 一样:

<bean id="myAspect" class="org.xyz.AspectModule">   <!-- configure properties of aspect here as normal --></bean>

3.2 声明一个切入点

一个切入点有助于确定使用不同建议执行的感兴趣的连接点(即方法)。在处理基于配置的 XML 架构时,切入点的声明有两个部分:

  • 一个切入点表达式决定了我们感兴趣的哪个方法会真正被执行。
  • 一个切入点标签包含一个名称和任意数量的参数。方法的真正内容是不相干的,并且实际上它应该是空的。

下面的示例中定义了一个名为 ‘businessService’ 的切入点,该切入点将与 com.xyz.myapp.service 包下的类中可用的每一个方法相匹配:

import org.aspectj.lang.annotation.Pointcut;@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression private void businessService() {}  // signature

下面的示例中定义了一个名为 ‘getname’ 的切入点,该切入点将与 com.tutorialspoint 包下的 Student 类中的 getName() 方法相匹配:

import org.aspectj.lang.annotation.Pointcut;@Pointcut("execution(* com.tutorialspoint.Student.getName(..))") private void getname() {}

3.3 声明建议

你可以使用 @{ADVICE-NAME} 注释声明五个建议中的任意一个,如下所示。这假设你已经定义了一个切入点标签方法 businessService():

@Before("businessService()")public void doBeforeTask(){ ...}@After("businessService()")public void doAfterTask(){ ...}@AfterReturning(pointcut = "businessService()", returning="retVal")public void doAfterReturnningTask(Object retVal){  // you can intercept retVal here.  ...}@AfterThrowing(pointcut = "businessService()", throwing="ex")public void doAfterThrowingTask(Exception ex){  // you can intercept thrown exception here.  ...}@Around("businessService()")public void doAroundTask(){ ...}

你可以为任意一个建议定义你的切入点内联。下面是在建议之前定义内联切入点的一个示例:

@Before("execution(* com.xyz.myapp.service.*.*(..))")public doBeforeTask(){ ...}

3.4 基于 AOP 的 @AspectJ 示例

为了理解上面提到的关于基于 AOP 的 @AspectJ 的概念,让我们编写一个示例,可以实现几个建议。为了在我们的示例中使用几个建议,让我们使 Eclipse IDE 处于工作状态,然后按照如下步骤创建一个 Spring 应用程序:

步骤描述
1创建一个名为 SpringExample 的项目,并且在所创建项目的 src 文件夹下创建一个名为 com.tutorialspoint 的包。
2使用 Add External JARs 选项添加所需的 Spring 库文件,就如在 Spring Hello World Example 章节中解释的那样。
3在项目中添加 Spring AOP 指定的库文件 aspectjrt.jar, aspectjweaver.jaraspectj.jar
4com.tutorialspoint 包下创建 Java 类 LoggingStudentMainApp
5src 文件夹下创建 Beans 配置文件 Beans.xml
6最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并且按如下解释的那样运行应用程序。

这里是 Logging.java 文件的内容。这实际上是 aspect 模块的一个示例,它定义了在各个点调用的方法。

package com.tutorialspoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Around;@Aspectpublic class Logging {   /** Following is the definition for a pointcut to select    *  all the methods available. So advice will be called    *  for all the methods.    */   @Pointcut("execution(* com.tutorialspoint.*.*(..))")   private void selectAll(){}   /**     * This is the method which I would like to execute    * before a selected method execution.    */   @Before("selectAll()")   public void beforeAdvice(){      System.out.println("Going to setup student profile.");   }   /**     * This is the method which I would like to execute    * after a selected method execution.    */   @After("selectAll()")   public void afterAdvice(){      System.out.println("Student profile has been setup.");   }   /**     * This is the method which I would like to execute    * when any method returns.    */   @AfterReturning(pointcut = "selectAll()", returning="retVal")   public void afterReturningAdvice(Object retVal){      System.out.println("Returning:" + retVal.toString() );   }   /**    * This is the method which I would like to execute    * if there is an exception raised by any method.    */   @AfterThrowing(pointcut = "selectAll()", throwing = "ex")   public void AfterThrowingAdvice(IllegalArgumentException ex){      System.out.println("There has been an exception: " + ex.toString());      }  }

下面是 Student.java 文件的内容:

package com.tutorialspoint;public class Student {   private Integer age;   private String name;   public void setAge(Integer age) {      this.age = age;   }   public Integer getAge() {      System.out.println("Age : " + age );      return age;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      System.out.println("Name : " + name );      return name;   }   public void printThrowException(){      System.out.println("Exception raised");      throw new IllegalArgumentException();   }}

下面是 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");      Student student = (Student) context.getBean("student");      student.getName();      student.getAge();           student.printThrowException();   }}

下面是配置文件 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"     xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">    <aop:aspectj-autoproxy/>   <!-- Definition for student bean -->   <bean id="student" class="com.tutorialspoint.Student">      <property name="name"  value="Zara" />      <property name="age"  value="11"/>         </bean>   <!-- Definition for logging aspect -->   <bean id="logging" class="com.tutorialspoint.Logging"/> </beans>

一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

Going to setup student profile.Name : ZaraStudent profile has been setup.Returning:ZaraGoing to setup student profile.Age : 11Student profile has been setup.Returning:11Going to setup student profile.Exception raisedStudent profile has been setup.There has been an exception: java.lang.IllegalArgumentException.....other exception content

四,spring的数据库开发

1. JDBC 框架概述

在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等。但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接。

所以当从数据库中获取数据时,你所做的是定义连接参数,指定要执行的 SQL 语句,每次迭代完成所需的工作。

Spring JDBC 提供几种方法和数据库中相应的不同的类与接口。我将给出使用 JdbcTemplate 类框架的经典和最受欢迎的方法。这是管理所有数据库通信和异常处理的中央框架类。

1.1 JdbcTemplate 类

JdbcTemplate 类执行 SQL 查询、更新语句和存储过程调用,执行迭代结果集和提取返回参数值。它也捕获 JDBC 异常并转换它们到 org.springframework.dao 包中定义的通用类、更多的信息、异常层次结构。

JdbcTemplate 类的实例是线程安全配置的。所以你可以配置 JdbcTemplate 的单个实例,然后将这个共享的引用安全地注入到多个 DAOs 中。

使用 JdbcTemplate 类时常见的做法是在你的 Spring 配置文件中配置数据源,然后共享数据源 bean 依赖注入到 DAO 类中,并在数据源的设值函数中创建了 JdbcTemplate。

1.2 配置数据源

我们在数据库 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));

现在,我们需要提供一个数据源到 JdbcTemplate 中,所以它可以配置本身来获得数据库访问。你可以在 XML 文件中配置数据源,其中一段代码如下所示:

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

1.3 数据访问对象(DAO)

DAO 代表常用的数据库交互的数据访问对象。DAOs 提供一种方法来读取数据并将数据写入到数据库中,它们应该通过一个接口显示此功能,应用程序的其余部分将访问它们。

在 Spring 中,数据访问对象(DAO)支持很容易用统一的方法使用数据访问技术,如 JDBC、Hibernate、JPA 或者 JDO。

1.4 执行 SQL 语句

我们看看如何使用 SQL 和 jdbcTemplate 对象在数据库表中执行 CRUD(创建、读取、更新和删除)操作。

查询一个整数类型:

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

1.5 执行 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 );

1.6 Spring JDBC 框架例子

基于上述概念,让我们看看一些重要的例子来帮助你理解在 Spring 中使用 JDBC 框架:

序号例子 & 描述
1Spring JDBC Example这个例子将解释如何编写一个简单的基于 Spring 应用程序的 JDBC。
2SQL Stored Procedure in Spring学习在使用 Spring 中的 JDBC 时如何调用 SQL 存储过程。

1.7 Spring JDBC 示例

想要理解带有 jdbc 模板类的 Spring JDBC 框架的相关概念,让我们编写一个简单的示例,来实现下述 Student 表的所有 CRUD 操作。

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

在继续之前,让我们适当地使用 Eclipse IDE 并按照如下所示的步骤创建一个 Spring 应用程序:

步骤描述
1创建一个名为 SpringExample 的项目,并在创建的项目中的 src 文件夹下创建包 com.tutorialspoint
2使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example 章节。
3在项目中添加 Spring JDBC 指定的最新的库 mysql-connector-java.jarorg.springframework.jdbc.jarorg.springframework.transaction.jar。如果这些库不存在,你可以下载它们。
4创建 DAO 接口 StudentDAO 并列出所有必需的方法。尽管这一步不是必需的而且你可以直接编写 StudentJDBCTemplate 类,但是作为一个好的实践,我们最好还是做这一步。
5com.tutorialspoint 包下创建其他的必需的 Java 类 StudentStudentMapperStudentJDBCTemplateMainApp
6确保你已经在 TEST 数据库中创建了 Student 表。并确保你的 MySQL 服务器运行正常,且你可以使用给出的用户名和密码读/写访问数据库。
7src 文件夹下创建 Beans 配置文件 Beans.xml
8最后一步是创建所有的 Java 文件和 Bean 配置文件的内容并按照如下所示的方法运行应用程序。

以下是数据访问对象接口文件 StudentDAO.java 的内容:

package com.tutorialspoint;import java.util.List;import javax.sql.DataSource;public interface StudentDAO {   /**     * This is the method to be used to initialize    * database resources ie. connection.    */   public void setDataSource(DataSource ds);   /**     * This is the method to be used to create    * a record in the Student table.    */   public void create(String name, Integer age);   /**     * This is the method to be used to list down    * a record from the Student table corresponding    * to a passed student id.    */   public Student getStudent(Integer id);   /**     * This is the method to be used to list down    * all the records from the Student table.    */   public List<Student> listStudents();   /**     * This is the method to be used to delete    * a record from the Student table corresponding    * to a passed student id.    */   public void delete(Integer id);   /**     * This is the method to be used to update    * a record into the Student table.    */   public void update(Integer id, Integer age);}

下面是 Student.java 文件的内容:

package com.tutorialspoint;public class Student {   private Integer age;   private String name;   private Integer id;   public void setAge(Integer age) {      this.age = age;   }   public Integer getAge() {      return age;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      return name;   }   public void setId(Integer id) {      this.id = id;   }   public Integer getId() {      return id;   }}

以下是 StudentMapper.java 文件的内容:

package com.tutorialspoint;import java.sql.ResultSet;import java.sql.SQLException;import org.springframework.jdbc.core.RowMapper;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;   }}

下面是为定义的 DAO 接口 StudentDAO 的实现类文件 StudentJDBCTemplate.java

package com.tutorialspoint;import java.util.List;import javax.sql.DataSource;import org.springframework.jdbc.core.JdbcTemplate;public class StudentJDBCTemplate implements StudentDAO {   private DataSource dataSource;   private JdbcTemplate jdbcTemplateObject;    public void setDataSource(DataSource dataSource) {      this.dataSource = dataSource;      this.jdbcTemplateObject = new JdbcTemplate(dataSource);   }   public void create(String name, Integer age) {      String SQL = "insert into Student (name, age) values (?, ?)";           jdbcTemplateObject.update( SQL, name, age);      System.out.println("Created Record Name = " + name + " Age = " + age);      return;   }   public Student getStudent(Integer id) {      String SQL = "select * from Student where id = ?";      Student student = jdbcTemplateObject.queryForObject(SQL,                         new Object[]{id}, new StudentMapper());      return student;   }   public List<Student> listStudents() {      String SQL = "select * from Student";      List <Student> students = jdbcTemplateObject.query(SQL,                                 new StudentMapper());      return students;   }   public void delete(Integer id){      String SQL = "delete from Student where id = ?";      jdbcTemplateObject.update(SQL, id);      System.out.println("Deleted Record with ID = " + id );      return;   }   public void update(Integer id, Integer age){      String SQL = "update Student set age = ? where id = ?";      jdbcTemplateObject.update(SQL, age, id);      System.out.println("Updated Record with ID = " + id );      return;   }}

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

package com.tutorialspoint;import java.util.List;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.tutorialspoint.StudentJDBCTemplate;public class MainApp {   public static void main(String[] args) {      ApplicationContext context =              new ClassPathXmlApplicationContext("Beans.xml");      StudentJDBCTemplate studentJDBCTemplate =       (StudentJDBCTemplate)context.getBean("studentJDBCTemplate");          System.out.println("------Records Creation--------" );      studentJDBCTemplate.create("Zara", 11);      studentJDBCTemplate.create("Nuha", 2);      studentJDBCTemplate.create("Ayan", 15);      System.out.println("------Listing Multiple Records--------" );      List<Student> students = studentJDBCTemplate.listStudents();      for (Student record : students) {         System.out.print("ID : " + record.getId() );         System.out.print(", Name : " + record.getName() );         System.out.println(", Age : " + record.getAge());      }      System.out.println("----Updating Record with ID = 2 -----" );      studentJDBCTemplate.update(2, 20);      System.out.println("----Listing Record with ID = 2 -----" );      Student student = studentJDBCTemplate.getStudent(2);      System.out.print("ID : " + student.getId() );      System.out.print(", Name : " + student.getName() );      System.out.println(", Age : " + student.getAge());         }}

下述是配置文件 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 ">   <!-- Initialization for data source -->   <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>   <!-- Definition for studentJDBCTemplate bean -->   <bean id="studentJDBCTemplate"       class="com.tutorialspoint.StudentJDBCTemplate">      <property name="dataSource"  ref="dataSource" />       </bean></beans>

当你完成创建源和 bean 配置文件后,运行应用程序。如果你的应用程序一切运行顺利的话,将会输出如下所示的消息:

------Records Creation--------Created Record Name = Zara Age = 11Created Record Name = Nuha Age = 2Created Record Name = Ayan Age = 15------Listing Multiple Records--------ID : 1, Name : Zara, Age : 11ID : 2, Name : Nuha, Age : 2ID : 3, Name : Ayan, Age : 15----Updating Record with ID = 2 -----Updated Record with ID = 2----Listing Record with ID = 2 -----ID : 2, Name : Nuha, Age : 20

你可以尝试自己删除在我的例子中我没有用到的操作,但是现在你有一个基于 Spring JDBC 框架的工作应用程序,你可以根据你的项目需求来扩展这个框架,添加复杂的功能。还有其他方法来访问你使用 NamedParameterJdbcTemplateSimpleJdbcTemplate 类的数据库,所以如果你有兴趣学习这些类的话,那么你可以查看 Spring 框架的参考手册。

五,spring的事务管理

1. 事务管理

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID

  • **原子性:**事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。
  • **一致性:**这表示数据库的引用完整性的一致性,表中唯一的主键等。
  • **隔离性:**可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。
  • **持久性:**一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:

  • 使用 begin transaction 命令开始事务。
  • 使用 SQL 查询语句执行各种删除、更新或插入操作。
  • 如果所有的操作都成功,则执行提交操作,否则回滚所有操作。

Spring 框架在不同的底层事务管理 APIs 的顶部提供了一个抽象层。Spring 的事务支持旨在通过添加事务能力到 POJOs 来提供给 EJB 事务一个选择方案。Spring 支持编程式和声明式事务管理。EJBs 需要一个应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现。

1.1 局部事务 vs. 全局事务

局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。

局部事务管理在一个集中的计算环境中是有用的,该计算环境中应用程序组件和资源位于一个单位点,而事务管理只涉及到一个运行在一个单一机器中的本地数据管理器。局部事务更容易实现。

全局事务管理需要在分布式计算环境中,所有的资源都分布在多个系统中。在这种情况下事务管理需要同时在局部和全局范围内进行。分布式或全局事务跨多个系统执行,它的执行需要全局事务管理系统和所有相关系统的局部数据管理人员之间的协调。

1.2 编程式 vs. 声明式

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

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。
  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代码控制事务。但作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。Spring 支持使用 Spring AOP 框架的声明式事务管理。

1.3 Spring 事务抽象

Spring事务管理的五大属性:隔离级别传播行为是否只读事务超时回滚规则

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;}
序号方法 & 描述
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();}
序号方法 & 描述
1**int getPropagationBehavior()**该方法返回传播行为。Spring 提供了与 EJB CMT 类似的所有的事务传播选项。
2**int getIsolationLevel()**该方法返回该事务独立于其他事务的工作的程度。
3**String getName()**该方法返回该事务的名称。
4**int getTimeout()**该方法返回以秒为单位的时间间隔,事务必须在该时间间隔内完成。
5**boolean isReadOnly()**该方法返回该事务是否是只读的。

下面是隔离级别的可能值:

序号隔离 & 描述
1TransactionDefinition.ISOLATION_DEFAULT这是默认的隔离级别。
2TransactionDefinition.ISOLATION_READ_COMMITTED表明能够阻止误读;可以发生不可重复读和虚读。
3TransactionDefinition.ISOLATION_READ_UNCOMMITTED表明可以发生误读、不可重复读和虚读。
4TransactionDefinition.ISOLATION_REPEATABLE_READ表明能够阻止误读和不可重复读;可以发生虚读。
5TransactionDefinition.ISOLATION_SERIALIZABLE表明能够阻止误读、不可重复读和虚读。

下面是传播类型的可能值:

序号传播 & 描述
1TransactionDefinition.PROPAGATION_MANDATORY支持当前事务;如果不存在当前事务,则抛出一个异常。
2TransactionDefinition.PROPAGATION_NESTED如果存在当前事务,则在一个嵌套的事务中执行。
3TransactionDefinition.PROPAGATION_NEVER不支持当前事务;如果存在当前事务,则抛出一个异常。
4TransactionDefinition.PROPAGATION_NOT_SUPPORTED不支持当前事务;而总是执行非事务性。
5TransactionDefinition.PROPAGATION_REQUIRED支持当前事务;如果不存在事务,则创建一个新的事务。
6TransactionDefinition.PROPAGATION_REQUIRES_NEW创建一个新事务,如果存在一个事务,则把当前事务挂起。
7TransactionDefinition.PROPAGATION_SUPPORTS支持当前事务;如果不存在,则执行非事务性。
8TransactionDefinition.TIMEOUT_DEFAULT使用默认超时的底层事务系统,或者如果不支持超时则没有。

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

public interface TransactionStatus extends SavepointManager {   boolean isNewTransaction();   boolean hasSavepoint();   void setRollbackOnly();   boolean isRollbackOnly();   boolean isCompleted();}
序号方法 & 描述
1**boolean hasSavepoint()**该方法返回该事务内部是否有一个保存点,也就是说,基于一个保存点已经创建了嵌套事务。
2**boolean isCompleted()**该方法返回该事务是否完成,也就是说,它是否已经提交或回滚。
3**boolean isNewTransaction()**在当前事务时新的情况下,该方法返回 true。
4**boolean isRollbackOnly()**该方法返回该事务是否已标记为 rollback-only。
5**void setRollbackOnly()**该方法设置该事务为 rollback-only 标记。

2. Spring 声明式事务管理

声明式事务管理方法允许你在配置的帮助下而不是源代码硬编程来管理事务。这意味着你可以将事务管理从事务代码中隔离出来。你可以只使用注释或基于配置的 XML 来管理事务。 bean 配置会指定事务型方法。下面是与声明式事务相关的步骤:

  • 我们使用标签,它创建一个事务处理的建议,同时,我们定义一个匹配所有方法的切入点,我们希望这些方法是事务型的并且会引用事务型的建议。
  • 如果在事务型配置中包含了一个方法的名称,那么创建的建议在调用方法之前就会在事务中开始进行。
  • 目标方法会在 try / catch 块中执行。
  • 如果方法正常结束,AOP 建议会成功的提交事务,否则它执行回滚操作。

让我们看看上述步骤是如何实现的。在我们开始之前,至少有两个数据库表是至关重要的,在事务的帮助下,我们可以实现各种 CRUD 操作。以 Student 表为例,该表是使用下述 DDL 在 MySQL TEST 数据库中创建的。

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

第二个表是 Marks,我们用来存储基于年份的学生标记。在这里,SID 是 Student 表的外键。

CREATE TABLE Marks(   SID INT NOT NULL,   MARKS  INT NOT NULL,   YEAR   INT NOT NULL);

现在让我们编写 Spring JDBC 应用程序来在 Student 和 Marks 表中实现简单的操作。让我们适当的使用 Eclipse IDE,并按照如下所示的步骤来创建一个 Spring 应用程序:

步骤描述
1创建一个名为 SpringExample 的项目,并在创建的项目中的 src 文件夹下创建包 com.tutorialspoint
2使用 Add External JARs 选项添加必需的 Spring 库,解释见 Spring Hello World Example chapter.
3在项目中添加其它必需的库 mysql-connector-java.jarorg.springframework.jdbc.jarorg.springframework.transaction.jar。如果你还没有这些库,你可以下载它们。
4创建 DAO 接口 StudentDAO 并列出所有需要的方法。尽管它不是必需的并且你可以直接编写 StudentJDBCTemplate 类,但是作为一个好的实践,我们还是做吧。
5com.tutorialspoint 包下创建其他必需的 Java 类 StudentMarksStudentMarksMapperStudentJDBCTemplateMainApp。如果需要的话,你可以创建其他的 POJO 类。
6确保你已经在 TEST 数据库中创建了 StudentMarks 表。还要确保你的 MySQL 服务器运行正常并且你使用给出的用户名和密码可以读/写访问数据库。
7src 文件夹下创建 Beans 配置文件 Beans.xml
8最后一步是创建所有 Java 文件和 Bean 配置文件的内容并按照如下所示的方法运行应用程序。

下面是数据访问对象接口文件 StudentDAO.java 的内容:

package com.tutorialspoint;import java.util.List;import javax.sql.DataSource;public interface StudentDAO {   /**     * This is the method to be used to initialize    * database resources ie. connection.    */   public void setDataSource(DataSource ds);   /**     * This is the method to be used to create    * a record in the Student and Marks tables.    */   public void create(String name, Integer age, Integer marks, Integer year);   /**     * This is the method to be used to list down    * all the records from the Student and Marks tables.    */   public List<StudentMarks> listStudents();}

以下是 StudentMarks.java 文件的内容:

package com.tutorialspoint;public class StudentMarks {   private Integer age;   private String name;   private Integer id;   private Integer marks;   private Integer year;   private Integer sid;   public void setAge(Integer age) {      this.age = age;   }   public Integer getAge() {      return age;   }   public void setName(String name) {      this.name = name;   }   public String getName() {      return name;   }   public void setId(Integer id) {      this.id = id;   }   public Integer getId() {      return id;   }   public void setMarks(Integer marks) {      this.marks = marks;   }   public Integer getMarks() {      return marks;   }   public void setYear(Integer year) {      this.year = year;   }   public Integer getYear() {      return year;   }   public void setSid(Integer sid) {      this.sid = sid;   }   public Integer getSid() {      return sid;   }}

下面是 StudentMarksMapper.java 文件的内容:

package com.tutorialspoint;import java.sql.ResultSet;import java.sql.SQLException;import org.springframework.jdbc.core.RowMapper;public class StudentMarksMapper implements RowMapper<StudentMarks> {   public StudentMarks mapRow(ResultSet rs, int rowNum) throws SQLException {      StudentMarks studentMarks = new StudentMarks();      studentMarks.setId(rs.getInt("id"));      studentMarks.setName(rs.getString("name"));      studentMarks.setAge(rs.getInt("age"));      studentMarks.setSid(rs.getInt("sid"));      studentMarks.setMarks(rs.getInt("marks"));      studentMarks.setYear(rs.getInt("year"));      return studentMarks;   }}

下面是定义的 DAO 接口 StudentDAO 实现类文件 StudentJDBCTemplate.java

package com.tutorialspoint;import java.util.List;import javax.sql.DataSource;import org.springframework.dao.DataAccessException;import org.springframework.jdbc.core.JdbcTemplate;public class StudentJDBCTemplate implements StudentDAO{   private JdbcTemplate jdbcTemplateObject;   public void setDataSource(DataSource dataSource) {      this.jdbcTemplateObject = new JdbcTemplate(dataSource);   }   public void create(String name, Integer age, Integer marks, Integer year){      try {         String SQL1 = "insert into Student (name, age) values (?, ?)";         jdbcTemplateObject.update( SQL1, name, age);         // Get the latest student id to be used in Marks table         String SQL2 = "select max(id) from Student";         int sid = jdbcTemplateObject.queryForInt( SQL2 );         String SQL3 = "insert into Marks(sid, marks, year) " +                        "values (?, ?, ?)";         jdbcTemplateObject.update( SQL3, sid, marks, year);         System.out.println("Created Name = " + name + ", Age = " + age);         // to simulate the exception.         throw new RuntimeException("simulate Error condition") ;      } catch (DataAccessException e) {         System.out.println("Error in creating record, rolling back");         throw e;      }   }   public List<StudentMarks> listStudents() {      String SQL = "select * from Student, Marks where Student.id=Marks.sid";      List <StudentMarks> studentMarks=jdbcTemplateObject.query(SQL,       new StudentMarksMapper());      return studentMarks;   }}

现在让我们改变主应用程序文件 MainApp.java,如下所示:

package com.tutorialspoint;import java.util.List;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");      StudentDAO studentJDBCTemplate =       (StudentDAO)context.getBean("studentJDBCTemplate");           System.out.println("------Records creation--------" );      studentJDBCTemplate.create("Zara", 11, 99, 2010);      studentJDBCTemplate.create("Nuha", 20, 97, 2010);      studentJDBCTemplate.create("Ayan", 25, 100, 2011);      System.out.println("------Listing all the records--------" );      List<StudentMarks> studentMarks = studentJDBCTemplate.listStudents();      for (StudentMarks record : studentMarks) {         System.out.print("ID : " + record.getId() );         System.out.print(", Name : " + record.getName() );         System.out.print(", Marks : " + record.getMarks());         System.out.print(", Year : " + record.getYear());         System.out.println(", Age : " + record.getAge());      }   }}

以下是配置文件 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"   xmlns:tx="http://www.springframework.org/schema/tx"   xmlns:aop="http://www.springframework.org/schema/aop"   xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    http://www.springframework.org/schema/tx   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd   http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">   <!-- Initialization for data source -->   <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="cohondob"/>   </bean>   <tx:advice id="txAdvice"  transaction-manager="transactionManager">      <tx:attributes>      <tx:method name="create"/>      </tx:attributes>   </tx:advice>   <aop:config>      <aop:pointcut id="createOperation"       expression="execution(* com.tutorialspoint.StudentJDBCTemplate.create(..))"/>      <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation"/>   </aop:config>   <!-- Initialization for TransactionManager -->   <bean id="transactionManager"   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">      <property name="dataSource"  ref="dataSource" />       </bean>   <!-- Definition for studentJDBCTemplate bean -->   <bean id="studentJDBCTemplate"     class="com.tutorialspoint.StudentJDBCTemplate">      <property name="dataSource"  ref="dataSource" />     </bean></beans>

当你完成了创建源和 bean 配置文件后,让我们运行应用程序。如果你的应用程序运行顺利的话,那么会输出如下所示的异常。在这种情况下,事务会回滚并且在数据库表中不会创建任何记录。

------Records creation--------Created Name = Zara, Age = 11Exception in thread "main" java.lang.RuntimeException: simulate Error condition

在删除异常后,你可以尝试上述示例,在这种情况下,会提交事务并且你可以在数据库中看见一条记录。

举报

相关推荐

0 条评论