详解Spring

一、Spring快速入门程序

接下来先看一个最简单的Spring项目构建过程

  1. 编写对象类(HelloWorld.java)
    在这里插入图片描述

  2. 根据对象类创建bean配置文件(Beans.xml)

  • 这个文件需要在 src 目录下创建。Beans.xml 用于给不同的 bean 分配唯一的 ID,并且控制不同值的对象的创建,而不会影响 Spring 的任何源文件。
  • 通过bean,将helloworld这个实例的name属性赋值为message,value赋值为Hello World!
    在这里插入图片描述
  1. 创建启动程序(MainApp.java)
  • 第一步是我们使用框架 API ClassPathXmlApplicationContext() 来创建应用程序的上下文。
  • 第二步是使用已创建的上下文的 getBean() 方法来获得所需的 bean。
    在这里插入图片描述

二、Spring IoC容器

容器

先介绍下IoC容器是什么

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

通过阅读配置元数据(Beans.xml)提供的指令,容器知道对哪些对象进行实例化,配置和组装。

上面的代码中,context对象加载Beans.xml配置文件,通过getBean(“helloword”)这个函数获得id=“helloword”的Beans实例。

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

  • 很容易发现,obj是通过getBean(“helloword”)获得一个对象的,而不是之前new一个对象获得。name\value这些属性字段也不再像之前那样通过new Helloword(“hello”, “world”)这种通过构造函数赋值获得。在"控制反转"之后,Spring容器通过bean配置获得了一个对象。

  • 简而言之,过去由程序员通过new对象(构造、set方法)形式转变为容器通过依赖注入(DI)类(bean配置)获得。

  • 容器有以下两类
    在这里插入图片描述

Spring 的 BeanFactory 容器

先来看看BeanFactory的定义

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

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

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

来看看入口函数中怎么使用容器的
在这里插入图片描述
在主程序当中,我们需要注意以下两点:

  • 第一步利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource() API 去加载在路径 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API 负责创建并初始化所有的对象,即在配置文件中提到的 bean。

  • 第二步利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象,该对象最后可以用于实际的对象。一旦得到这个对象,你就可以利用这个对象来调用任何方法。

Spring ApplicationContext 容器

Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。
Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

和BeanFactory的区别

它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。 ApplicationContext 包含
BeanFactory 所有的功能,一般情况下,相对于BeanFactory,ApplicationContext会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

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

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

使用FileSystemXmlApplicationContext例子:
在这里插入图片描述

  • 第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext API 去生成工厂 bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean 配置文件中的 bean。

  • 第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

在第一章中用的是ClassPathXmlApplicationContext,在这一节中用的是FileSystemXmlApplicationContext,在之后章节使用WebXmlApplicationContext

Bean

Spring Bean 定义

这部分讲解如何编写bean.xml配置文件。

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

  1. bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:
  • 如何创建一个 bean
  • bean 的生命周期的详细信息
  • bean 的依赖关系

在这里插入图片描述

  1. bean与spring 容器之间的关系
    在这里插入图片描述

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

  • 基于 XML 的配置文件(Beans.xml)
  • 基于注解的配置(@Autowrite)
  • 基于 Java 的配置(@Configuration)

Spring Bean 作用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring

在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton。

Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session,5种作用域说明如下所示
注意,如果你使用 web-aware ApplicationContext 时,其中三个是可用的。
在这里插入图片描述

Singleon作用域
singleton 是默认的作用域。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了。Spring IoC容器只会创建该bean定义的唯一实例,只要id与该bean定义相匹配,则只会返回bean的同一实例。

prototype 作用域
Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。

在这里插入图片描述

Spring Bean 生命周期

Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
声明带有 init-method 和/或 destroy-method 参数的 。init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。

举个栗子:
对象类文件
在这里插入图片描述

Beans.xml 文件:
在这里插入图片描述
这里使用了是AbstractApplicationContext,它可以调用关闭 hook 的 registerShutdownHook() 方法。它将确保正常关闭,并且调用相关的 destroy 方法。
在这里插入图片描述
程序输出
在这里插入图片描述

如果你有太多具有相同名称的初始化或者销毁方法的 Bean,那么你不需要在每一个 bean 上声明初始化方法和销毁方法。框架使用 元素中的 default-init-method 和 default-destroy-method 属性提供了灵活地配置这种情况
在这里插入图片描述

三、Spring 依赖注入

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

过去要在一个对象中引用另一个对象是这么写的:
在这里插入图片描述
在控制反转的场景中,我们反而会做这样的事情:
在这里插入图片描述

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

在这里,我们已经从 TextEditor 中删除了全面控制,并且把它保存到其他地方(即 XML 配置文件),且依赖关系(即 SpellChecker 类)通过类构造函数被注入到 TextEditor 类中。因此,控制流通过依赖注入(DI)已经“反转”,因为你已经有效地委托依赖关系到一些外部系统。

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

DI 主要有两种变体和下面的两个子章将结合实例涵盖它们
在这里插入图片描述

依赖注入有基于构造函数、基于setter函数注入形式

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

首先举个栗子:
一个依赖类文件 SpellChecker.java,被TextEditor类调用
在这里插入图片描述
TextEditor.java 文件的内容:
在这里插入图片描述
配置文件 Beans.xml 的内容,它有基于构造函数注入的配置:
在这里插入图片描述
以下是 MainApp.java 文件的内容:
在这里插入图片描述

  • 看到这大家也就明白了,首先IoC容器通过getBean获得TestEditor类,实例化TestEditor的Bean时,发现有依赖类SpellCheck类,故需先实例化SpellCheck的bean,将其通过构造函数注入到TestEditor的Bean中,这里使用的是constructor-arg ref="">来配置的(引用对象是ref,普通值为value属性)。相当于过去的new TestEditor(new SpellCheck())。

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

再检查一下我们传递给构造函数不同类型的位置。考虑下面的类:
在这里插入图片描述
如果你使用 type 属性显式的指定了构造函数参数的类型,容器也可以使用与简单类型匹配的类型。例如:
在这里插入图片描述
最后并且也是最好的传递构造函数参数的方式,使用 index 属性来显式的指定构造函数参数的索引。下面是基于索引为 0 的例子,如下所示:

在这里插入图片描述
如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,如果你想要直接传递,那么你应该使用如上所示的 value 属性

Spring 基于setter函数的依赖注入

TextEditor.java 文件的内容:
构造
在这里插入图片描述
设值
在这里插入图片描述
要设置一个变量 spellChecker,我们使用 setSpellChecker() 方法,该方法与 Java POJO 类非常相似。

依赖类文件 SpellChecker.java
在这里插入图片描述

下面是配置文件 Beans.xml 的内容,该文件有基于设值函数注入的配置:
在这里插入图片描述
唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。

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

使用 p-namespace 实现 XML 配置:
以带有 标签的标准 XML 配置文件为例:
在这里插入图片描述
上述 XML 配置文件可以使用 p-namespace 以一种更简洁的方式重写,如下所示:
在这里插入图片描述

Spring 注入内部 Beans

基于设值函数的依赖注入还可以有另一种写法。正如你所知道的 Java 内部类是在其他类的范围内被定义的,同理,inner beans 是在其他 bean 的范围内定义的 bean。因此在 或 元素内 元素被称为内部bean,如下所示。

TextEditor.java 文件的内容:
在这里插入图片描述
依赖的类文件 SpellChecker.java 内容:
在这里插入图片描述
使用内部 bean 为基于 setter 注入进行配置的配置文件 Beans.xml 文件:
在这里插入图片描述
之前写法将spellChecker类分出来
在这里插入图片描述

Spring注入集合

如果你想传递多个值,如 Java Collection 类型 List、Set、Map 和 Properties,应该怎么做呢。为了处理这种情况,Spring 提供了四种类型的集合的配置元素,如下所示:
在这里插入图片描述
栗子:
JavaCollection.java 文件的内容:
在这里插入图片描述
配置所有类型的集合的配置文件 Beans.xml 文件:
在这里插入图片描述
在这里插入图片描述
MainApp.java内容
在这里插入图片描述

注入 Bean 引用
下面的 Bean 定义将帮助你理解如何注入 bean 的引用作为集合的元素。甚至你可以将引用和值混合在一起,如下所示:

在这里插入图片描述
在这里插入图片描述
为了使用上面的 bean 定义,你需要定义 setter 方法,它们应该也能够是用这种方式来处理引用

在这里插入图片描述

四、Spring Beans 自动装配

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

自动装配模式
你可以使用元素的 autowire 属性为一个 bean 定义指定自动装配模式。
在这里插入图片描述

自动装配的局限性
在这里插入图片描述

Spring 自动装配 byName

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

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

TextEditor.java 文件的内容:
在这里插入图片描述
依赖类文件 SpellChecker.java 的内容:
在这里插入图片描述
下面是 MainApp.java 文件的内容:
在这里插入图片描述
下面是在正常情况下的配置文件 Beans.xml 文件:
在这里插入图片描述
使用自动装配 “byName”,那么你的 XML 配置文件将成为如下:
在这里插入图片描述
可以发现使用autowire 与不使用的区别在于是否需要显示引用。 beans 的 auto-wire 属性设置为 byName后,尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。

Spring 自动装配 byType

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

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

普通配置
在这里插入图片描述
自动装配 “byType”,那么你的 XML 配置文件将成为如下:
在这里插入图片描述

Spring 由构造函数自动装配

前两种都是基于设值函数依赖注入的,由构造函数自动装配基于构造函数依赖注入。

这种模式与 byType 非常相似,但它应用于构造器参数。Spring 容器看作 beans,在 XML 配置文件中 beans 的autowire 属性设置为 constructor。然后,它尝试把它的构造函数的参数与配置文件中 beans名称中的一个进行匹配和连线。如果找到匹配项,它会注入这些 bean,否则,它会抛出异常。

例如,在配置文件中,如果一个 bean 定义设置为通过构造函数自动装配,而且它有一个带有 SpellChecker 类型的参数之一的构造函数,那么 Spring 就会查找定义名为 SpellChecker 的 bean,并用它来设置构造函数的参数。你仍然可以使用 标签连接其余属性。下面的例子将说明这个概念。

TextEditor.java 文件的内容:
在这里插入图片描述
依赖类文件 SpellChecker.java 的内容:
在这里插入图片描述
正常情况下的配置文件 Beans.xml 文件:
在这里插入图片描述
使用自动装配 “by constructor”,那么你的 XML 配置文件将成为如下:
在这里插入图片描述

五、Spring 基于注解的配置

常用注解
在这里插入图片描述

Spring @Required 注释

@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML配置文件中,否则容器就会抛出一BeanInitializationException 异常。下面显示的是一个使用 @Required注释的示例。
Student.java 文件的内容:
在这里插入图片描述

MainApp.java 文件的内容:
在这里插入图片描述
配置文件 Beans.xml: 文件的内容:(缺少age配置)
在这里插入图片描述
引起 BeanInitializationException 异常,并且会输出一下错误信息和其他日志消息:
在这里插入图片描述
“age” 属性中删除了注释,将正常
在这里插入图片描述

Spring @Autowired 注释

@Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。
@Autowired 注释可以在 setter 方法中被用于自动连接 bean,就像 @Autowired 注释,容器,一个属性或者任意命名的可能带有多个参数的方法。

Setter 方法中的 @Autowired
你可以在 XML 文件中的 setter 方法中使用 @Autowired 注释来除去 元素。当 Spring遇到一个在 setter 方法中使用的 @Autowired 注释,它会在方法中视图执行 byType 自动连接。

TextEditor.java 文件的内容:
在这里插入图片描述
SpellChecker.java 的内容:
在这里插入图片描述
配置文件 Beans.xml:
在这里插入图片描述

属性中的 @Autowired
在属性上注解@Autowired。Spring 会将这些传递过来的值或者引用自动分配给那些属性。
在这里插入图片描述
配置文件 Beans.xml:
在这里插入图片描述

构造函数中的 @Autowired

在构造函数中使用 @Autowired。一个构造函数 @Autowired 说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。
在这里插入图片描述
配置文件 Beans.xml:
在这里插入图片描述

@Autowired 的(required=false)选项

默认情况下,@Autowired 注释意味着依赖是必须的,它类似于 @Required 注释,然而,你可以使用 @Autowired 的 (required=false) 选项关闭默认行为。

即使你不为 age 属性传递任何参数,下面的示例也会成功运行,但是对于 name 属性则需要一个参数。你可以自己尝试一下这个示例,因为除了只有 Student.java 文件被修改以外,它和 @Required 注释示例是相似的。

在这里插入图片描述

Spring @Qualifier 注释

可能会有这样一种情况,当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。下面显示的是使用 @Qualifier 注释的一个示例。

Student.java 文件的内容:
在这里插入图片描述
Profile.java 文件的内容:
在这里插入图片描述
MainApp.java 文件的内容:
在这里插入图片描述
配置文件 Beans.xml 的示例:
在这里插入图片描述
使用属性@Autowired注解,故Profile的bean中不需要写Student的配置。由于@Qualifier(“student1”)注解表明注入到Profile对象的是student1。

六、基于 Java 的配置

基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大多数的 Spring,但是一些有帮助的基于 Java 的注解

@Configuration 和 @Bean 注解

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

在这里插入图片描述
之前的章节都在介绍依赖注入的内容,通过bean配置硬编码的为一些属性对象赋值,但这样做明细不符合开发的合理性,很多属性我们可能都是动态获得的,从数据库中读取或者前端返回。@Configuration 在某个类中注解,比如Controller类,表示对象的值可以从该类中动态获取;那么比如动态获取的是某个对象,使用@Bean注解即可达到和在xml文件中配置bean的目的。

在这里插入图片描述

  • 在这里,带有 @Bean 注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean。你的配置类可以声明多个 @Bean。

一旦定义了配置类,你就可以使用 AnnotationConfigApplicationContext 来加载并把他们提供给 Spring 容器。
在这里插入图片描述
对比下之前的Main
在这里插入图片描述
可以加载各种配置类,如下所示:
在这里插入图片描述
举个栗子
HelloWorld.java 文件的内容:
在这里插入图片描述

HelloWorldConfig.java 文件的内容: 在这里插入图片描述
下面是 MainApp.java 文件的内容:
在这里插入图片描述
注入 Bean 的依赖性
@Beans 依赖对方时,表达这种依赖性非常简单,只要有一个 bean 方法调用另一个,如下所示:
在这里插入图片描述
对比之前xml配置
在这里插入图片描述
再来个栗子:
TextEditor.java 文件的内容:
在这里插入图片描述
依赖的类文件 SpellChecker.java 的内容:
在这里插入图片描述
TextEditorConfig.java 文件的内容:
在这里插入图片描述
MainApp.java 文件的内容:
在这里插入图片描述
生命周期回调
@Bean 注解支持指定任意的初始化和销毁的回调方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和销毁方法的属性:
在这里插入图片描述
指定 Bean 的范围:

默认范围是单实例,但是你可以重写带有 @Scope 注解的该方法,如下所示:

在这里插入图片描述

@Import 注解:

@import 注解允许从另一个配置类中加载 @Bean 定义。考虑 ConfigA 类,如下所示:
在这里插入图片描述
当实例化上下文时,不需要同时指定 ConfigA.class 和 ConfigB.class,只有 ConfigB 类需要提供,如下所示:
在这里插入图片描述

七、Spring 中的事件处理

你已经看到了在所有章节中 Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期。当加载 beans 时,ApplicationContext 发布某些类型的事件。例如,当上下文启动时,ContextStartedEvent 发布,当上下文停止时,ContextStoppedEvent 发布

通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。

在这里插入图片描述
由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。

监听上下文事件

为了监听上下文事件,一个 bean 应该实现只有一个方法 onApplicationEvent() 的 ApplicationListener 接口。因此,我们写一个例子来看看事件是如何传播的,以及如何可以用代码来执行基于某些事件所需的任务。

HelloWorld.java 文件的内容:
在这里插入图片描述
CStartEventHandler.java 文件的内容:
在这里插入图片描述
CStopEventHandler.java 文件的内容:
在这里插入图片描述
MainApp.java 文件的内容:
在这里插入图片描述
配置文件 Beans.xml 文件:
在这里插入图片描述

八、Spring 框架的 AOP

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

AOP 术语
在我们开始使用 AOP 工作之前,让我们熟悉一下 AOP 概念和术语。这些术语并不特定于 Spring,而是与 AOP 有关的。
在这里插入图片描述
通知的类型
Spring 方面可以使用下面提到的五种通知工作:
在这里插入图片描述
实现自定义方面
Spring 支持 @AspectJ annotation style 的方法和基于模式的方法来实现自定义方面。这两种方法已经在下面两个子节进行了详细解释。
在这里插入图片描述

Spring 中基于 AOP 的 XML架构

声明一个 aspect
在这里插入图片描述
声明一个Join Point
在这里插入图片描述
在这里插入图片描述
声明Advice
可以使用 <aop:{ADVICE NAME}> 元素在一个 中声明五个建议中的任何一个,如下所示:
在这里插入图片描述
你可以对不同的建议使用相同的 doRequiredTask 或者不同的方法。这些方法将会作为 aspect 模块的一部分来定义.

基于 AOP 的 XML 架构的示例
Logging.java 文件,aspect 模块的一个示例,它定义了在各个点调用的方法。
在这里插入图片描述
在这里插入图片描述
Student.java 文件的内容:
在这里插入图片描述
MainApp.java 文件的内容:
在这里插入图片描述
配置文件 Beans.xml:
在这里插入图片描述
在这里插入图片描述

Spring 中基于 AOP 的 @Aspect

Logging.java 文件的内容
在这里插入图片描述
在这里插入图片描述
配置文件 Beans.xml:
在这里插入图片描述
Student.java 文件的内容:
在这里插入图片描述
MainApp.java 文件的内容:
在这里插入图片描述

九、Spring JDBC 框架

JdbcTemplate 类

JdbcTemplate 类执行 SQL 查询、更新语句和存储过程调用,执行迭代结果集和提取返回参数值。它也捕获 JDBC 异常并转换它们到 org.springframework.dao 包中定义的通用类、更多的信息、异常层次结构。
JdbcTemplate 类的实例是线程安全配置的。所以你可以配置 JdbcTemplate 的单个实例,然后将这个共享的引用安全地注入到多个 DAOs 中。
使用 JdbcTemplate 类时常见的做法是在你的 Spring 配置文件中配置数据源,然后共享数据源 bean 依赖注入到 DAO 类中,并在数据源的设值函数中创建了 JdbcTemplate。

提供一个数据源到 JdbcTemplate 中,所以它可以配置本身来获得数据库访问。你可以在 XML 文件中配置数据源,其中一段代码如下所示:
在这里插入图片描述
数据访问对象(DAO)

DAO 代表常用的数据库交互的数据访问对象。DAOs 提供一种方法来读取数据并将数据写入到数据库中,它们应该通过一个接口显示此功能,应用程序的其余部分将访问它们。
在 Spring 中,数据访问对象(DAO)支持很容易用统一的方法使用数据访问技术,如 JDBC、Hibernate、JPA 或者 JDO。

执行 SQL 语句
jdbcTemplateObject.queryForObject(SQL, 参数, 返回类型);
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
执行 DDL 语句
可以使用 jdbcTemplate 中的 execute(…) 方法来执行任何 SQL 语句或 DDL 语句。下面是一个使用 CREATE 语句创建一个表的示例:
在这里插入图片描述
示例
Student.java 文件的内容:
在这里插入图片描述
StudentMapper.java 文件的内容:
在这里插入图片描述
数据访问对象接口文件 StudentDAO.java 的内容:
在这里插入图片描述
在这里插入图片描述
为定义的 DAO 接口 StudentDAO 的实现类文件 StudentJDBCTemplate.java:

在这里插入图片描述
配置文件 Beans.xml 的内容:
在这里插入图片描述

MainApp.java 文件的内容:
在这里插入图片描述

十、Spring 事务管理

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

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

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

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

局部事物 vs. 全局事务

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

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

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

编程式 vs. 声明式
Spring 支持两种类型的事务管理:

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。

  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

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

Spring 事务抽象
Spring 事务抽象的关键是由 org.springframework.transaction.PlatformTransactionManager 接口定义,如下所示:
在这里插入图片描述
在这里插入图片描述
TransactionDefinition 是在 Spring 中事务支持的核心接口,它的定义如下:
在这里插入图片描述
TransactionDefinition 是在 Spring 中事务支持的核心接口,它的定义如下:
在这里插入图片描述
下面是隔离级别的可能值:
在这里插入图片描述
下面是传播类型的可能值:
在这里插入图片描述
TransactionStatus 接口为事务代码提供了一个简单的方法来控制事务的执行和查询事务状态。
在这里插入图片描述
在这里插入图片描述

Spring 编程式事务管理

编程式事务管理方法允许你在对你的源代码编程的帮助下管理事务。这给了你极大地灵活性,但是它很难维护。

让我们直接使用 PlatformTransactionManager 来实现编程式方法从而实现事务。要开始一个新事务,你需要有一个带有适当的 transaction 属性的 TransactionDefinition 的实例。这个例子中,我们使用默认的 transaction 属性简单的创建了 DefaultTransactionDefinition 的一个实例。

当 TransactionDefinition 创建后,你可以通过调用 getTransaction() 方法来开始你的事务,该方法会返回 TransactionStatus 的一个实例。 TransactionStatus 对象帮助追踪当前的事务状态,并且最终,如果一切运行顺利,你可以使用 PlatformTransactionManager 的 commit() 方法来提交这个事务,否则的话,你可以使用 rollback() 方法来回滚整个操作。

StudentMarks.java 文件的内容:
在这里插入图片描述
数据访问对象接口文件 StudentDAO.java 的内容:
在这里插入图片描述
DAO 接口 StudentDAO 实现类文件 StudentJDBCTemplate.java:
在这里插入图片描述
在这里插入图片描述
MainApp.java
在这里插入图片描述
配置文件 Beans.xml 的内容
在这里插入图片描述

Spring 声明式事务管理

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

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

例子与前面代码差不多,更改的是以下地方
DAO 接口 StudentDAO 实现类文件 StudentJDBCTemplate.java
在这里插入图片描述
配置文件 Beans.xml 的内容增加以下内容
在这里插入图片描述

十一、Spring Web MVC 框架

Spring web MVC 框架提供了模型-视图-控制的体系结构和可以用来开发灵活、松散耦合的 web 应用程序的组件。MVC 模式导致了应用程序的不同方面(输入逻辑、业务逻辑和 UI 逻辑)的分离,同时提供了在这些元素之间的松散耦合。

  • 模型封装了应用程序数据,并且通常它们由 POJO 组成。
  • 视图主要用于呈现模型数据,并且通常它生成客户端的浏览器可以解释的 HTML 输出。
  • 控制器主要用于处理用户请求,并且构建合适的模型并将其传递到视图呈现

DispatcherServlet

Spring Web 模型-视图-控制(MVC)框架是围绕 DispatcherServlet 设计的,DispatcherServlet 用来处理所有的 HTTP 请求和响应。Spring Web MVC DispatcherServlet 的请求处理的工作流程如下图所示:
在这里插入图片描述
下面是对应于 DispatcherServlet 传入 HTTP 请求的事件序列:
收到一个 HTTP 请求后,DispatcherServlet 根据 HandlerMapping 来选择并且调用适当的控制器。

  • 控制器接受请求,并基于使用的 GET 或 POST 方法来调用适当的 service 方法。Service 方法将设置基于定义的业务逻辑的模型数据,并返回视图名称到 DispatcherServlet 中。
  • DispatcherServlet 会从 ViewResolver 获取帮助,为请求检取定义视图。
  • 一旦确定视图,DispatcherServlet 将把模型数据传递给视图,最后呈现在浏览器中。
    上面所提到的所有组件,即 HandlerMapping、Controller 和 ViewResolver 是 WebApplicationContext 的一部分,而 WebApplicationContext 是带有一些对 web 应用程序必要的额外特性的 ApplicationContext 的扩展。

需求的配置
需要映射你想让 DispatcherServlet 处理的请求,通过使用在 web.xml 文件中的一个 URL 映射。

web.xml 文件将被保留在你的应用程序的 WebContent/WEB-INF 目录下。好的,在初始化 HelloWeb DispatcherServlet 时,该框架将尝试加载位于该应用程序的 WebContent/WEB-INF 目录中文件名为 [servlet-name]-servlet.xml 的应用程序内容。在这种情况下,我们的文件将是 HelloWeb-servlet.xml。

接下来, 标签表明哪些 URLs 将被 DispatcherServlet 处理。这里所有以 .jsp 结束的 HTTP 请求将由 HelloWeb DispatcherServle t处理。

如果你不想使用默认文件名 [servlet-name]-servlet.xml 和默认位置 WebContent/WEB-INF,你可以通过在 web.xml 文件中添加 servlet 监听器 ContextLoaderListener 自定义该文件的名称和位置,如下所示:
在这里插入图片描述
检查 HelloWeb-servlet.xml 文件的请求配置,该文件位于 web 应用程序的 WebContent/WEB-INF 目录下:
在这里插入图片描述
以下是关于 HelloWeb-servlet.xml 文件的一些要点:

  • [servlet-name]-servlet.xml 文件将用于创建 bean 定义,重新定义在全局范围内具有相同名称的任何已定义的 bean。

  • 标签将用于激活 Spring MVC 注释扫描功能,该功能允许使用注释,如 @Controller 和 @RequestMapping 等等。

  • InternalResourceViewResolver 将使用定义的规则来解决视图名称。按照上述定义的规则,一个名称为 hello 的逻辑视图将发送给位于 /WEB-INF/jsp/hello.jsp 中实现的视图。

定义控制器
DispatcherServlet 发送请求到控制器中执行特定的功能。@Controller 注释表明一个特定类是一个控制器的作用。@RequestMapping 注释用于映射 URL 到整个类或一个特定的处理方法。
在这里插入图片描述
@Controller 注释定义该类作为一个 Spring MVC 控制器。在这里,第一次使用的 @RequestMapping 表明在该控制器中处理的所有方法都是相对于 /hello 路径的。下一个注释 @RequestMapping(method = RequestMethod.GET) 用于声明 printHello() 方法作为控制器的默认 service 方法来处理 HTTP GET 请求。你可以在相同的 URL 中定义其他方法来处理任何 POST 请求。

可以用另一种形式来编写上面的控制器,你可以在 @RequestMapping 中添加额外的属性,如下所示:
在这里插入图片描述
创建 JSP 视图
对于不同的表示技术,Spring MVC 支持许多类型的视图。这些包括 JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 提要、JasperReports 等等。但我们最常使用利用 JSTL 编写的 JSP 模板。所以让我们在 /WEB-INF/hello/hello.jsp 中编写一个简单的 hello 视图:
在这里插入图片描述

Spring Web MVC例子

HelloController.java 文件的内容:
在这里插入图片描述
web.xml 的内容
在这里插入图片描述
HelloWeb-servlet.xml 的内容
在这里插入图片描述

发布了14 篇原创文章 · 获赞 3 · 访问量 607

猜你喜欢

转载自blog.csdn.net/qq_41011723/article/details/104876729