diff --git a/docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md b/docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md
index e18e760f..fe060066 100644
--- a/docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md
+++ b/docs/system-design/framework/spring/spring-knowledge-and-questions-summary.md
@@ -9,71 +9,84 @@ tag:
下面的很多问题我自己在使用 Spring 的过程中也并没有注意,自己也是临时查阅了很多资料和书籍补上的。网上也有一些很多关于 Spring 常见问题/面试题整理的文章,我感觉大部分都是互相 copy,而且很多问题也不是很好,有些回答也存在问题。所以,自己花了一周的业余时间整理了一下,希望对大家有帮助。
-## 什么是 Spring 框架?
+## Spring 基础
+
+### 什么是 Spring 框架?
Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
-Spring 翻译过来就是春天的意思,可见其目标和使命就是为 Java 程序员带来春天啊!感动!
-
-> 题外话 : 语言的流行通常需要一个杀手级的应用,Spring 就是 Java 生态的一个杀手级的应用框架。
-
-我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。
-
-比如说 Spring 自带 IoC(Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。
+我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,比如说 Spring 支持 IoC(Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。

-Spring 最核心的思想就是不重新造轮子,开箱即用!
+Spring 最核心的思想就是不重新造轮子,开箱即用,提高开发效率。
+
+Spring 翻译过来就是春天的意思,可见其目标和使命就是为 Java 程序员带来春天啊!感动!
+
+🤐 多提一嘴 : **语言的流行通常需要一个杀手级的应用,Spring 就是 Java 生态的一个杀手级的应用框架。**
Spring 提供的核心功能主要是 IoC 和 AOP。学习 Spring ,一定要把 IoC 和 AOP 的核心思想搞懂!
- Spring 官网:
- Github 地址: https://github.com/spring-projects/spring-framework
-## 列举一些重要的 Spring 模块?
+### Spring 包含的模块有哪些?
-下图对应的是 Spring4.x 版本。目前最新的 5.x 版本中 Web 模块的 Portlet 组件已经被废弃掉,同时增加了用于异步响应式处理的 WebFlux 组件。
+**Spring4.x 版本** :
-
+
-**Spring Core**
+**Spring5.x 版本** :
-核心模块, Spring 其他所有的功能基本都需要依赖于该模块,主要提供 IoC 依赖注入功能的支持。
+
-**Spring Aspects**
+Spring5.x 版本中 Web 模块的 Portlet 组件已经被废弃掉,同时增加了用于异步响应式处理的 WebFlux 组件。
-该模块为与 AspectJ 的集成提供支持。
+Spring 各个模块的依赖关系如下:
-**Spring AOP**
+
-提供了面向切面的编程实现。
+#### Core Container
-**Spring Data Access/Integration :**
+Spring 框架的核心模块,也可以说是基础模块,主要提供 IoC 依赖注入功能的支持。Spring 其他所有的功能基本都需要依赖于该模块,我们从上面那张 Spring 各个模块的依赖关系图就可以看出来。
-Spring Data Access/Integration 由 5 个模块组成:
+- **spring-core** :Spring 框架基本的核心工具类。
+- **spring-beans** :提供对 bean 的创建、配置和管理等功能的支持。
+- **spring-context** :提供对国际化、事件传播、资源加载等功能的支持。
+- **spring-expression** :提供对表达式语言(Spring Expression Language) SpEL 的支持,只依赖于 core 模块,不依赖于其他模块,可以单独使用。
-- spring-jdbc : 提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
-- spring-tx : 提供对事务的支持。
-- spring-orm : 提供对 Hibernate 等 ORM 框架的支持。
-- spring-oxm : 提供对 Castor 等 OXM 框架的支持。
-- spring-jms : Java 消息服务。
+#### AOP
-**Spring Web**
+- **spring-aspects** :该模块为与 AspectJ 的集成提供支持。
+- **spring-aop** :提供了面向切面的编程实现。
+- **spring-instrument** :提供了为 JVM 添加代理(agent)的功能。 具体来讲,它为 Tomcat 提供了一个织入代理,能够为 Tomcat 传递类文 件,就像这些文件是被类加载器加载的一样。没有理解也没关系,这个模块的使用场景非常有限。
-Spring Web 由 4 个模块组成:
+#### Data Access/Integration
-- spring-web :对 Web 功能的实现提供一些最基础的支持。
-- spring-webmvc : 提供对 Spring MVC 的实现。
-- spring-websocket : 提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
-- spring-webflux :提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步.
+- **spring-jdbc** :提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
+- **spring-tx** :提供对事务的支持。
+- **spring-orm** : 提供对 Hibernate、JPA 、iBatis 等 ORM 框架的支持。
+- **spring-oxm** :提供一个抽象层支撑 OXM(Object-to-XML-Mapping),例如:JAXB、Castor、XMLBeans、JiBX 和 XStream 等。
+- **spring-jms** : 消息服务。自 Spring Framework 4.1 以后,它还提供了对 spring-messaging 模块的继承。
-**Spring Test**
+#### Spring Web
+
+- **spring-web** :对 Web 功能的实现提供一些最基础的支持。
+- **spring-webmvc** : 提供对 Spring MVC 的实现。
+- **spring-websocket** : 提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
+- **spring-webflux** :提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步。
+
+#### Messaging
+
+**spring-messaging** 是从 Spring4.0 开始新加入的一个模块,主要职责是为 Spring 框架集成一些基础的报文传送应用。
+
+#### Spring Test
Spring 团队提倡测试驱动开发(TDD)。有了控制反转 (IoC)的帮助,单元测试和集成测试变得更简单。
Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)、Mockito(主要用来 Mock 对象)、PowerMock(解决 Mockito 的问题比如无法模拟 final, static, private 方法)等等常用的测试框架支持的都比较好。
-## Spring,Spring MVC,Spring Boot 之间什么关系?
+### Spring,Spring MVC,Spring Boot 之间什么关系?
很多人对 Spring,Spring MVC,Spring Boot 这三者傻傻分不清楚!这里简单介绍一下这三者,其实很简单,没有什么高深的东西。
@@ -93,7 +106,7 @@ Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot 旨在简化 Spr
Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,真正做到开箱即用!
-## Spring IOC & AOP
+## Spring IoC
### 谈谈自己对于 Spring IoC 的了解
@@ -119,26 +132,6 @@ Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉
- [IoC 源码阅读](https://javadoop.com/post/spring-ioc)
- [面试被问了几百遍的 IoC 和 AOP ,还在傻傻搞不清楚?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486938&idx=1&sn=c99ef0233f39a5ffc1b98c81e02dfcd4&chksm=cea24211f9d5cb07fa901183ba4d96187820713a72387788408040822ffb2ed575d28e953ce7&token=1736772241&lang=zh_CN#rd)
-### 谈谈自己对于 AOP 的了解
-
-AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
-
-Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 **JDK Proxy**,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 **Cglib** 生成一个被代理对象的子类来作为代理,如下图所示:
-
-
-
-当然你也可以使用 **AspectJ** !Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
-
-### Spring AOP 和 AspectJ AOP 有什么区别?
-
-**Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。** Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
-
-Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
-
-如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。
-
-## Spring Bean
-
### 什么是 Spring Bean?
简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象。
@@ -218,7 +211,7 @@ Spring 内置的 `@Autowired` 以及 JDK 内置的 `@Resource` 和 `@Inject` 都
| `@Resource` | `javax.annotation` | Java JSR-250 |
| `@Inject` | `javax.inject` | Java JSR-330 |
- `@Autowired` 和`@Resource`使用的比较多一些。
+`@Autowired` 和`@Resource`使用的比较多一些。
### @Autowired 和 @Resource 的区别是什么?
@@ -287,11 +280,12 @@ private SmsService smsService;
Spring 中 Bean 的作用域通常有下面几种:
-- **singleton** : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
-- **prototype** : 每次请求都会创建一个新的 bean 实例。
-- **request** : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
-- **session** : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
-- **global-session** : 全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
+- **singleton** : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
+- **prototype** : 每次获取都会创建一个新的 bean 实例。也就是说,连续 `getBean()` 两次,得到的是不同的 Bean 实例。
+- **request** (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
+- **session** (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
+- **application/global-session** (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),,该 bean 仅在当前应用启动时间内有效。
+- **websocket** (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
**如何配置 bean 的作用域呢?**
@@ -348,6 +342,75 @@ public Person personPrototype() {

+## Spring AoP
+
+### 谈谈自己对于 AOP 的了解
+
+AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
+
+Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 **JDK Proxy**,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 **Cglib** 生成一个被代理对象的子类来作为代理,如下图所示:
+
+
+
+当然你也可以使用 **AspectJ** !Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
+
+AOP 切面编程设计到的一些专业术语:
+
+| 术语 | 含义 |
+| :---------------- | :----------------------------------------------------------: |
+| 目标(Target) | 被通知的对象 |
+| 代理(Proxy) | 向目标对象应用通知之后创建的代理对象 |
+| 连接点(JoinPoint) | 目标对象的所属类中,定义的所有方法均为连接点 |
+| 切入点(Pointcut) | 被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点) |
+| 通知(Advice) | 增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情 |
+| 切面(Aspect) | 切入点(Pointcut)+通知(Advice) |
+| Weaving(织入) | 将通知应用到目标对象,进而生成代理对象的过程动作 |
+
+### Spring AOP 和 AspectJ AOP 有什么区别?
+
+**Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。** Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
+
+Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
+
+如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。
+
+### AspectJ 定义的通知类型有哪些?
+
+- **Before**(前置通知):目标对象的方法调用之前触发
+- **After** (后置通知):目标对象的方法调用之后触发
+- **AfterReturning**(返回通知):目标对象的方法调用完成,在返回结果值之后触发
+- **AfterThrowing**(异常通知) :目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
+- **Around**: (环绕通知)编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法
+
+### 多个切面的执行顺序如何控制?
+
+1、通常使用`@Order` 注解直接定义切面顺序
+
+```java
+// 值越小优先级越高
+@Order(3)
+@Component
+@Aspect
+public class LoggingAspect implements Ordered {
+```
+
+**2、实现`Ordered` 接口重写 `getOrder` 方法。**
+
+```java
+@Component
+@Aspect
+public class LoggingAspect implements Ordered {
+
+ // ....
+
+ @Override
+ public int getOrder() {
+ // 返回值越小优先级越高
+ return 1;
+ }
+}
+```
+
## Spring MVC
### 说说自己对于 Spring MVC 了解?
@@ -390,6 +453,16 @@ Model2 模式下还存在很多问题,Model2 的抽象和封装程度还远远
MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的 Web 层的开发,并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service 层(处理业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(控制层,返回数据给前台页面)。
+### Spring MVC 的核心组件有哪些?
+
+记住了下面这些组件,也就记住了 SpringMVC 的工作原理。
+
+- **`DispatcherServlet`** :**核心的中央处理器**,负责接收请求、分发,并给予客户端响应。
+- **`HandlerMapping`** :**处理器映射器**,根据 uri 去匹配查找能处理的 `Handler` ,并会将请求涉及到的拦截器和 `Handler` 一起封装。
+- **`HandlerAdapter`** :**处理器适配器**,根据 `HandlerMapping` 找到的 `Handler` ,适配执行对应的 `Handler`;
+- **`Handler`** :**请求处理器**,处理实际请求的处理器。
+- **`ViewResolver`** :**视图解析器**,根据 `Handler` 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 `DispatcherServlet` 响应客户端
+
### SpringMVC 工作原理了解吗?
**Spring MVC 原理如下图所示:**
@@ -400,14 +473,63 @@ MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring
**流程说明(重要):**
-1. 客户端(浏览器)发送请求,直接请求到 `DispatcherServlet`。
-2. `DispatcherServlet` 根据请求信息调用 `HandlerMapping`,解析请求对应的 `Handler`。
-3. 解析到对应的 `Handler`(也就是我们平常说的 `Controller` 控制器)后,开始由 `HandlerAdapter` 适配器处理。
-4. `HandlerAdapter` 会根据 `Handler`来调用真正的处理器开处理请求,并处理相应的业务逻辑。
-5. 处理器处理完业务后,会返回一个 `ModelAndView` 对象,`Model` 是返回的数据对象,`View` 是个逻辑上的 `View`。
-6. `ViewResolver` 会根据逻辑 `View` 查找实际的 `View`。
-7. `DispaterServlet` 把返回的 `Model` 传给 `View`(视图渲染)。
-8. 把 `View` 返回给请求者(浏览器)
+1. 客户端(浏览器)发送请求, `DispatcherServlet`拦截请求。
+2. `DispatcherServlet` 根据请求信息调用 `HandlerMapping` 。`HandlerMapping` 根据 uri 去匹配查找能处理的 `Handler`(也就是我们平常说的 `Controller` 控制器) ,并会将请求涉及到的拦截器和 `Handler` 一起封装。
+3. `DispatcherServlet` 调用 `HandlerAdapter`适配执行 `Handler` 。
+4. `Handler` 完成对用户请求的处理后,会返回一个 `ModelAndView` 对象给`DispatcherServlet`,`ModelAndView` 顾名思义,包含了数据模型以及相应的视图的信息。`Model` 是返回的数据对象,`View` 是个逻辑上的 `View`。
+5. `ViewResolver` 会根据逻辑 `View` 查找实际的 `View`。
+6. `DispaterServlet` 把返回的 `Model` 传给 `View`(视图渲染)。
+7. 把 `View` 返回给请求者(浏览器)
+
+### 统一异常处理怎么做?
+
+推荐使用注解的方式统一异常处理,具体会使用到 `@ControllerAdvice` + `@ExceptionHandler` 这两个注解 。
+
+```java
+@ControllerAdvice
+@ResponseBody
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(BaseException.class)
+ public ResponseEntity> handleAppException(BaseException ex, HttpServletRequest request) {
+ //......
+ }
+
+ @ExceptionHandler(value = ResourceNotFoundException.class)
+ public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) {
+ //......
+ }
+}
+```
+
+这种异常处理方式下,会给所有或者指定的 `Controller` 织入异常处理的逻辑(AOP),当 `Controller` 中的方法抛出异常的时候,由被`@ExceptionHandler` 注解修饰的方法进行处理。
+
+`ExceptionHandlerMethodResolver` 中 `getMappedMethod` 方法决定了异常具体被哪个被 `@ExceptionHandler` 注解修饰的方法处理异常。
+
+```java
+@Nullable
+ private Method getMappedMethod(Class extends Throwable> exceptionType) {
+ List> matches = new ArrayList<>();
+ //找到可以处理的所有异常信息。mappedMethods 中存放了异常和处理异常的方法的对应关系
+ for (Class extends Throwable> mappedException : this.mappedMethods.keySet()) {
+ if (mappedException.isAssignableFrom(exceptionType)) {
+ matches.add(mappedException);
+ }
+ }
+ // 不为空说明有方法处理异常
+ if (!matches.isEmpty()) {
+ // 按照匹配程度从小到大排序
+ matches.sort(new ExceptionDepthComparator(exceptionType));
+ // 返回处理异常的方法
+ return this.mappedMethods.get(matches.get(0));
+ }
+ else {
+ return null;
+ }
+ }
+```
+
+从源代码看出:**`getMappedMethod()`会首先找到可以匹配处理异常的所有方法信息,然后对其进行从小到大的排序,最后取最小的那一个匹配的方法(即匹配度最高的那个)。**
## Spring 框架中用到了哪些设计模式?
@@ -550,6 +672,7 @@ String transient4; // not persistent because of @Transient
## 参考
- 《Spring 技术内幕》
+- 《从零开始深入学习 Spring》:https://juejin.cn/book/6857911863016390663
-
-
-