Spring4实战读书笔记

Spring4实战读书笔记

首先,我们需要明白,为什么我们需要引入Spring,也就是说Spring的好处。个人觉得主要是在于两方面解耦和对bean的管理。

第一部分:Spring核心

共分为四个章节:

Spring4实战读书笔记_第1张图片

第一章节:Spring之旅

相当于对整个Spring框架进行了整体概括,如

  1. spring的容器
  2. spring的核心模块
  3. spring的生态系统
  4. spring的新功能

Spring是如何简化我们开发的

  1. DI (依赖注入 dependency injection)
  2. AOP(面向切面编程 aspect- oriented programming)
  3. 使用模板消除样板式代码

依赖注入(DI)

什么是DI(dependency injection)

来源于百度百科:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中 。

代码演示:

@RunWith( SpringJUnit4ClassRunner. class)
@ContextConfiguration( classes= AspectConfig.class)
public class TestMain {
    @Autowired
    private Performance performance;

    @Test
    public void testOne(){
        System.out.println(performance);
        performance.perform();
    }
}

通俗点说:当我们依赖某一个类的时候不再去手动new创建对象,而是通过Spring来帮我们创建。

面向切面编程(AOP)

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

总结:DI能够让相互协作的软件组件保持松散耦合,而面向切面编程( aspect- oriented programming, AOP) 允许你把遍布应用各处的功能分离出来形成可重用的组件。

样板式代码

Spring旨在通过模板封装来消除样板式代码。 如Spring对jdbc的链接操作做的 JdbcTemplate 封装,其他的还有诸如Redis,JMS,MongoDB等等。

Spring容器

在 基于 Spring 的 应用 中, 你的 应用 对象 生 存于 Spring 容器( container) 中。 如图 1. 4 所示, Spring 容器 负责 创建 对象, 装配 它们, 配置 它们 并 管理 它们 的 整个 生命 周期, 从 生存 到 死亡( 在这里, 可能 就是 new 到 finalize())。

Spring4实战读书笔记_第2张图片

Spring容器分类:

Bean工厂: 由 org. springframework. beans. factory. BeanFactory 接口 定义, 是最 简单 的 容器, 提供 基本 的 DI 支持。

应用上下文: 由 org. springframework. context. ApplicationContext 接口 定义, 基于 BeanFactory 构建, 并提 供应 用 框架 级别 的 服务, 例如 从属 性 文件 解析 文本 信息 以及 发布 应用 事件 给 感兴趣 的 事件 监听 者。

Spring自带了多种类型的应用上下文

AnnotationConfigApplicationContext: 从 一个 或 多个 基于 Java 的 配置 类 中 加载 Spring 应用 上下文。

AnnotationConfigWebApplicationContext: 从 一个 或 多个 基于 Java 的 配置 类 中 加载 Spring Web 应用 上下文。

ClassPathXmlApplicationContext: 从 类 路径 下 的 一个 或 多个 XML 配置文件 中 加载 上下文 定义, 把 应用 上下文 的 定义 文件 作为 类 资源。

FileSystemXmlapplicationcontext: 从文 件 系统 下 的 一个 或 多个 XML 配置文件 中 加载 上下文 定义。

XmlWebApplicationContext: 从 Web 应用 下 的 一个 或 多个 XML 配置文件 中 加载 上下文 定义。

bean的生命周期

传统bean的生命周期:

在 传统 的 Java 应用 中, bean 的 生命 周期 很 简单。 使用 Java 关键字 new 进行 bean 实例 化, 然后 该 bean 就可 以使 用了。 一旦 该 bean 不再 被 使用, 则由 Java 自动 进行 垃圾 回收。

Spring的bean的生命周期

Spring4实战读书笔记_第3张图片

Spring模块

Spring4实战读书笔记_第4张图片

Spring模块-Spring核心容器

容器 是 Spring 框架 最 核心 的 部分, 它 管理 着 Spring 应用 中 bean 的 创建、 配置 和 管理。 在 该 模块 中, 包括了 Spring bean 工厂, 它为 Spring 提供 了 DI 的 功能。 基于 bean 工厂, 我们 还会 发现 有 多种 Spring 应用 上下文 的 实现, 每一种 都 提供 了 配置 Spring 的 不同 方式。 除了 bean 工厂 和 应用 上下文, 该 模块 也 提供 了 许多 企业 服务, 例如 E- mail、 JNDI 访问、 EJB 集成 和 调度。 所有 的 Spring 模块 都 构建 于 核心 容器 之上。 当你 配置 应用 时, 其实 你 隐式 地 使用 了 这些 类。

Spring模块-Spring的AOP模块

在 AOP 模块 中, Spring 对面 向 切面 编程 提供 了 丰富 的 支持。 这个 模块 是 Spring 应用 系统 中 开发 切面 的 基础。 与 DI 一样, AOP 可以 帮助 应用 对象 解 耦。 借助于 AOP, 可以 将 遍布 系统 的 关注 点( 例如 事务 和 安全) 从 它们 所 应用 的 对象 中 解 耦 出来。

Spring模块-数据访问与集成

对于各种通用样板式代码进行了封装。对常用第三方服务进行了整合,如JMS,Redis

Spring模块-Web与远程调用

SpringMvc

Spring模块-Instrumentation

Spring 的 Instrumentation 模块 提供 了 为 JVM 添加 代理( agent) 的 功能。 具体 来讲, 它为 Tomcat 提供 了 一个 织入 代理, 能够 为 Tomcat 传递 类 文件, 就 像 这些 文件 是 被 类 加载 器 加载 的 一样。

Spring模块-测试

鉴于 开发者 自 测 的 重要性, Spring 提供 了 测试 模块 以 致力于 Spring 应用 的 测试。

第二章节:装配Bean

本章内容:

  1. 声明bean
  2. 构造器注入和set方法注入
  3. 装配bean
  4. 控制bean的创建和销毁

当我们实现某个功能当前类还需要引入某种服务并且这种服务是由其他类提供的,这时我们需要创建应用对象和服务对象,而这种实现某种业务功能而创建对象那么这种对象之间的协作关系称之为装配,也是依赖注入的本质。

Spring三种主要的Bean装配机制

在XML中进行显示配置

在JAVA中进行显示配置

隐式bean发现机制和自动装配

通常不限制使用哪种方式,某些极端场景需要多种形式配合才行。

自动化装配bean

自动化装配实际是与xml的显示配置的一种区分,实际效果都是一样的。

实现自动化装配bean的方式:

组件扫描:Spring 会 自动 发现 应用 上下文 中 所 创建 的 bean。

自动装配:Spring 自动 满足 bean 之间 的 依赖。 这里有按类型或按id注入的实现

@Component 注解

这个 简单 的 注解 表明 该类 会 作为 组件 类, 并 告知 Spring 要 为 这个 类 创建 bean。

@ComponentScan 注解

默认 会 扫描 与 配置 类 相同 的包以 及 这个 包 下 的 所有 子 包,与xml的里面的

< context: component- scan base- package=" com.hand" />的效果是一致的。

可以配置同时扫描多个包

为组件扫描的bean命名

Spring 应用 上下 文中 所有 的 bean 都会 给定 一个 ID。就是 将 类 名 的 第一个 字母 变为 小写。 如果 想 为 这个 bean 设置 不同 的 ID, 你 所 要做 的 就是 将 期望 的 ID 作为 值 传递 给@ Component 注解。做法如下:

@Component("audience")
public class Audience {}

Spring 支持 将@ Named 作为@ Component 注解 的 替代 方案。 两者之间 有 一些 细微 的 差异, 但是 在 大多数 场景 中, 它们 是 可以 互相 替换 的。

bean实现自动装配

bean如何实现自动自动装配

自动装配 就是 让 Spring 自动 满足 bean 依赖 的 一种 方法, 在 满足 依赖 的 过程中, 会在 Spring 应用 上下 文中 寻找 匹配 某个 bean 需求 的 其他 bean。 为了 声明 要 进行 自动 装配, 我们 可以 借助 Spring 的@ Autowired 注解。

**值得注意的是:**如果 没有 匹配 的 bean, 那么 在 应用 上下文 创建 的 时候, Spring 会 抛出 一个 异常。 为了 避免 异常 的 出现, 你 可以 将@ Autowired 的 required 属性 设置 为 false:

@RunWith( SpringJUnit4ClassRunner. class)
@ContextConfiguration( classes= AspectConfig.class)
public class TestMain {
    @Autowired(required = false)
    private Performance performance;

    @Test
    public void testOne(){
        System.out.println(performance);
        performance.perform();
    }
}

**自动装配带来的歧义性:**将 required 属性 设置 为 false 时, Spring 会 尝试 执行 自动 装配, 但是 如果 没有 匹配 的 bean 的 话, Spring 将会 让 这个 bean 处于 未 装配 的 状态。 但是, 把 required 属性 设置 为 false 时, 你 需要 谨慎 对待。 如果 在 你的 代码 中 没有 进行 null 检查 的 话, 这个 处于 未 装配 状态 的 属性 有可能 会 出现 NullPointerException。 如果 有 多个 bean 都能 满足 依赖 关系 的 话, Spring 将会 抛出 一个 异常, 表明 没有 明确 指定 要 选择 哪个 bean 进行 自动 装配。

@Inject

@Inject 注解 来源于 Java 依赖 注入 规范, 该 规范 同时 还为 我们 定义 了@ Named 注解。 在 自动 装配 中, Spring 同时 支持@ Inject 和@ Autowired。 尽管@ Inject 和@ Autowired 之间 有着 一些 细微 的 差别, 但是 在 大多数 场景 下, 它们 都是 可以 互相 替换 的。

相对于传统的xml配置方式,Spring支持纯代码的形式进行配置,也就是JavaConfig

@ Configuration

@ Configuration 注解 表明 这个 类 是一 个 配置 类,JavaConfig也是通过它来实现的。

@Bean

@Bean 注解 会 告诉 Spring 这个 方法 将会 返回 一个 对象, 该 对象 要 注册 为 Spring 应用 上下文 中的 bean。 方法 体中 包含 了 最终 产生 bean 实例 的 逻辑。

通过xml形式bean的方式不再赘述,基本上javaConfig都能对xml配置进行代替

第三章节-高级装配

主要内容

  1. Spring profile
  2. 条件化的bean声明
  3. 自动装配与歧义性
  4. bean的作用域
  5. Spring表达式语言

spring profile

spring profile与maven profile的意义某种程度上来说是相同的,这里不做赘述

条件化的bean声明

条件化bean的声明:一个 或 多个 bean 只有 在 应 用的 类 路径 下 包含 特 定的 库 时 才 创建。 或者 我们 希望 某个 bean 只有 当 另外 某个 特定 的 bean 也 声明 了 之后 才会 创建。 我们 还可能 要求 只有 某个 特定 的 环境 变量 设置 之后, 才会 创建 某个 bean。 在 Spring 4 之前, 很难 实现 这种 级别 的 条件 化 配置, 但是 Spring 4 引入 了 一个 新的@ Conditional 注解,可以用来实现这种需求。

自动装配的歧义性:

首先需要明确的是@Autowired是按类型进行的装配

**何时会出现自动装配的歧义性:**仅有 一个 bean 匹配 所需 的 结果 时, 自动 装配 才是 有效 的。 如果不 仅有 一个 bean 能够 匹配 结果 的 话, 这种 歧义 性 会 阻碍 Spring 自动 装配 属性、 构造 器 参数 或 方法 参数,并且会抛出NoUniqueBeanDefinitionException。

如何解决自动装配的歧义性

既然有多个可选,某种程度上来说这多个bean还是存在区别。在spring中可以通过将 可选 bean 中的 某一个 设为 首选( primary) 的 bean, 或者 使用 限定 符( qualifier) 来 帮助 Spring 将 可选 的 bean 的 范围 缩小 到 只有 一个 bean。

@Primary
public class SgtPeppers implements CompactDisc {
}
//或者
@Bean 
@Primary 
public Dessert iceCream() {}

当@Primary仍然不能满足我们的需求时,可以尝试使用@Qualifier

@Autowired 

@Qualifier(" iceCream")

public void setDessert( Dessert dessert) { this. dessert = dessert; }

因为spring不允许一个类里面同一个注解出现多次,当所有能用的注解都用上之后还存在歧义性,这个时候你需要自定义注解了。Java 8 允许 出现 重复 的 注解, 只要 这个 注解 本身 在 定义 的 时候 带有@ Repeatable 注解 就可以。 不过, Spring 的@ Qualifier 注解 并没有 在 定义 时 添加@ Repeatable 注解。

bean的作用域

在 默认 情况下, Spring 应用 上下 文中 所有 bean 都是 作为 以 单 例( singleton) 的 形式 创建 的。 也就是说, 不管 给定 的 一个 bean 被 注入 到 其他 bean 多少 次, 每次 所 注入 的 都是 同一个 实例。

默认是单例的,而对象调用的方法都是会独立开辟空间的。

单 例( Singleton): 在 整个 应用 中, 只 创建 bean 的 一个 实例。

原型( Prototype): 每次 注入 或者 通过 Spring 应用 上下文 获取 的 时候, 都会 创建 一个 新的 bean 实例。

会话( Session): 在 Web 应用 中, 为 每个 会话 创建 一个 bean 实例。

请求( Rquest): 在 Web 应用 中, 为 每个 请求 创建 一个 bean 实例。

单例的实现方式:

@Component

@Scope( ConfigurableBeanFactory. SCOPE_ PROTOTYPE) 

public class Notepad { ... }

第四章节-面向切面的Spring

主要内容:

面向切面编程的基本原理

通过POJO来创建切面

使用@Aspect注解

为AspectJ切面注入依赖

如果 让 应用 对象 只 关注 于 自己 所 针对 的 业务 领域 问题, 而 其他 方面 的 问题 由其 他 应用 对象 来 处理。

横切关注点

在 软件 开发 中, 散布 于 应用 中 多处 的 功能 被称为 横 切 关注 点

简而言之, 横 切 关注 点 可以 被 描述 为 影响 应用 多处 的 功能,而切面可以用来实现横切关注点。

下图的安全就可以称之为横切关注点

Spring4实战读书笔记_第5张图片

常见实现通用功能的方式:
继承

委托

切面

AOP术语

通知( Advice)

通知 定义 了 切面 是什么 以及 何时 使用。 除了 描述 切面 要 完成 的 工作, 通知 还 解决 了 何时 执行 这个 工作 的 问题。 它 应该 应用 在某 个 方法 被 调用 之前? 之后? 之前 和 之后 都 调用? 还是 只在 方法 抛出 异常 时调 用?

Spring 切面 可以 应用 5 种 类型 的 通知:

前置 通知( Before): 在 目标 方法 被 调用 之前 调用 通知 功能;

后置 通知( After): 在 目标 方法 完成 之后 调用 通知, 此时 不会 关心 方法 的 输出 是什么;

返回 通知( After- returning): 在 目标 方法 成功 执行 之后 调用 通知;

异常 通知( After- throwing): 在 目标 方法 抛出 异常 后 调用 通知;

环绕 通知( Around): 通知 包裹 了 被 通知 的 方法, 在被 通知 的 方法 调用 之前 和 调用 之后 执行 自定义 的 行为。

连接点( Join point)

Craig Walls 沃尔斯. Spring实战(第4版)(异步图书) (Kindle 位置 2864-2865). 人民邮电出版社. Kindle 版本.

连接 点 是在 应用 执行 过程中 能够 插入 切面 的 一个 点。 这个 点 可以 是 调用 方法 时、 抛出 异常 时、 甚至 修改 一个 字段 时。 切面 代码 可以 利用 这些 点 插入 到 应用 的 正常 流程 之中, 并 添加 新的 行为。

切点( Poincut)

切点 的 定义 会 匹配 通知 所要 织入 的 一个 或 多个 连接 点。 我们 通常 使用 明确 的 类 和 方法 名称, 或是 利用 正 则 表达式 定义 所 匹配 的 类 和 方法 名称 来 指定 这些 切点。

切面( Aspect)

切面 是 通知 和 切点 的 结合。 通知 和 切点 共同 定义 了 切面 的 全部 内容—— 它是 什么, 在 何时 和 何处 完成 其 功能。

引入( Introduction)

引入 允许 我们 向 现 有的 类 添加 新方法 或 属性。

织入( Weaving)

织入 是把 切面 应用 到 目标 对象 并 创建 新的 代理 对象 的 过程。 切面 在 指定 的 连 接点 被 织入 到 目标 对象 中。 在 目标 对象 的 生命 周期 里 有 多个 点 可以 进行 织入:

编译 期: 切面 在 目标 类 编译 时 被 织入。 这种 方式 需要 特殊 的 编译器。 AspectJ 的 织入 编译器 就是 以 这种 方式 织入 切面 的。

类 加载 期: 切面 在 目标 类 加载 到 JVM 时 被 织入。 这种 方式 需要 特殊 的 类 加载 器( ClassLoader), 它可 以在 目标 类 被 引入 应用 之前 增强 该 目标 类 的 字节 码。 AspectJ 5 的 加载 时 织入( load- time weaving, LTW) 就 支持 以 这种 方式 织入 切面。

运行 期: 切面 在 应用 运行 的 某个 时刻 被 织入。 一般 情况下, 在 织入 切面 时, AOP 容器 会为 目标 对象 动态 地 创建 一个 代理

Spring实现的切面是变体, Spring AOP 构建 在 动态 代理 基础 之上, 因此, Spring 对 AOP 的 支持 局限于 方法 拦截。

Spring 在 运行时 通知 对象

通过 在 代理 类 中 包裹 切面, Spring 在 运 行期 把 切面 织入 到 Spring 管理 的 bean 中。 如图 4. 3 所示, 代理 类 封装 了 目标 类, 并 拦截 被 通知 方法 的 调用, 再把 调用 转发 给 真正 的 目标 bean。 当代 理 拦截 到 方法 调用 时, 在调 用 目标 bean 方法 之前, 会 执行 切面 逻辑。

Spring4实战读书笔记_第6张图片

直到 应用 需要 被 代理 的 bean 时, Spring 才 创建 代理 对象。 如果 使 用的 是 ApplicationContext 的 话, 在 ApplicationContext 从 BeanFactory 中 加载 所有 bean 的 时候, Spring 才会 创建 被 代理 的 对象。 因为 Spring 运行时 才 创建 代理 对象, 所以 我们 不需要 特殊 的 编译器 来 织入 Spring AOP 的 切面。

切点表达式

Spring4实战读书笔记_第7张图片

切面的实现

注解的形式

xml的形式

你可能感兴趣的:(spring实战,Spring实战读书笔记,spring实战)