大家好我是小明,今天复习框架
文章目录
- [1. Spring框架中的单例bean是线程安全的吗??](#1. Spring框架中的单例bean是线程安全的吗??)
- [2. AOP(面向切面编程)&& Spring中的事务是如何实现的](#2. AOP(面向切面编程)&& Spring中的事务是如何实现的)
- [3. Spring事务失效的场景有哪些?](#3. Spring事务失效的场景有哪些?)
- [4. Spring的bean的生命周期](#4. Spring的bean的生命周期)
- [5. Spring的循环引用](#5. Spring的循环引用)
- [6. SpringMVC的执行流程](#6. SpringMVC的执行流程)
- [7. Spring的自动配置原理(最高频的面试题之一)](#7. Spring的自动配置原理(最高频的面试题之一))
总体复习路线

1. Spring框架中的单例bean是线程安全的吗??
Spring框架中的bean是单例的吗?
答:的确是单例
Spring框架中的单例bean是线程安全的吗??
不是线程安全的
count是一定有线程安全问题的,但是比如注入的service成员变量是变不了的

Spring bean并没有可变的状态(比如说Service类和DAO类),所以说某种程度上说Spring的单例bean是线程安全的。
2. AOP(面向切面编程)&& Spring中的事务是如何实现的
在不修改原有业务代码的前提下,给程序的【指定方法】统一增加通用功能的技术,核心就是AOP。
常见AOP使用场景
- 记录操作日志
- 缓存处理
举个例子:
记录操作日志:使用AOP环绕通知+切点表达式,通过环绕通知获取请求方法的参数,获取到参数数之后,保存到数据库;
还有比如说java的redis这一套注解也是AOP还有MyBatis操作Mysql数据这个一套注解。
Spring中的事务是如何实现的??
本质就是通过AOP功能,对方法前后进行拦截,在执行方法之前开始事务,执行完目标方法后根据执行的情况进行事务的提交或者回滚。
3. Spring事务失效的场景有哪些?
- 异常的捕获处理

异常捕获处理之后,事务处理以为没有报错,就不会回滚,执行到哪里就到哪里。
解决办法:可以将异常抛出,比如说,异常捕获以后new Exception
- 抛出检查异常

解决办法:

- 非public方法导致事务失效

原因:Spring为方法的创建代理,添加事务通知,前提条件都是该方法时public的
总结:
① 异常捕获处理,自己处理了异常,没有抛出,解决:手动抛出
② 抛出检查异常,配置 rollbackFor 属性为 Exception
③ 非 public 方法导致的事务失效,改为 public
4. Spring的bean的生命周期
这个死记就好

生命周期简约版
① 通过 BeanDefinition 获取 bean 的定义信息
② 调用构造函数实例化 bean
③ bean 的依赖注入
④ 处理 Aware 接口 (BeanNameAware、BeanFactoryAware、ApplicationContextAware)
⑤ Bean 的后置处理器 BeanPostProcessor - 前置
⑥ 初始化方法 (InitializingBean、init-method)
⑦ Bean 的后置处理器 BeanPostProcessor - 后置
详细版
Spring Bean的完整生命周期执行步骤如下,顺序固定:
① 通过 BeanDefinition 获取bean的定义信息:读取Bean的配置信息(比如@Component、@Bean),确定Bean的类型、作用域、依赖关系等;
② 调用构造函数实例化 bean:Spring根据BeanDefinition的信息,通过反射调用构造方法,创建Bean的实例对象(相当于new一个对象);
③ bean 的依赖注入:为Bean的属性赋值,完成依赖注入(比如@Autowired注入Mapper、Service),解决Bean之间的依赖关系;
④ 处理 Aware 接口 (BeanNameAware、BeanFactoryAware、ApplicationContextAware):让当前Bean获取Spring容器的核心资源,比如BeanNameAware拿到自身的bean名称,ApplicationContextAware拿到Spring上下文对象;
⑤ Bean 的后置处理器 BeanPostProcessor - 前置处理:在Bean初始化方法执行前,对Bean做自定义增强处理,无返回值;
⑥ 执行初始化方法 (InitializingBean接口的afterPropertiesSet方法、xml配置的init-method、@PostConstruct注解):Bean初始化的核心步骤,用来做资源初始化(比如初始化连接池、加载配置文件);
⑦ Bean 的后置处理器 BeanPostProcessor - 后置处理:在Bean初始化完成后做增强,Spring AOP的动态代理就是在这一步实现的 ,返回增强后的代理对象;
⑧ Bean进入就绪状态,开始对外提供服务:此时Bean已经完全创建完成,可以正常调用;
⑨ 容器关闭时执行销毁方法 (DisposableBean接口的destroy方法、xml配置的destroy-method、@PreDestroy注解):释放Bean占用的资源(比如关闭数据库连接、线程池)。
5. Spring的循环引用
循环引用: 类之间相互依赖注入
举个例子:


Spring框架是如何解决的??
三级缓存


那么是不是不需要三级缓存了呢??
假如说A是单例,那就不行了,那他怎么解决循环依赖问题;

这张图为什么要把代理对象放到二级缓存里面呢??
因为A是单例的,不能再次实例化一个代理对象;后面想使用就直接使用二级缓存的代理对象;
构造方法注入出现循环依赖
这种Spring解决不了,原因:用于bean的生命周期中构造函数是第一个执行的,Spring框架并不能解决构造函数的依赖注入
解决方案:
使用@Lazy进行懒加载,什么时候需要该对象在进行创建。

6. SpringMVC的执行流程
前提:前后端分离开发
执行流程图:

执行步骤:
- 用户发送出请求到前端控制器 DispatcherServlet
- DispatcherServlet 收到请求调用 HandlerMapping(处理器映射器)
- HandlerMapping 找到具体的处理器,生成处理器对象及处理器拦截器 (如果有),再一起返回给 DispatcherServlet
- DispatcherServlet 调用 HandlerAdapter(处理器适配器)
- HandlerAdapter 经过适配调用具体的处理器(Handler/Controller)
- 方法上添加了 @ResponseBody
- 通过 HttpMessageConverter 来返回结果转换为 JSON 并响应
7. Spring的自动配置原理(最高频的面试题之一)
- 在 Spring Boot 项目中的引导类上有一个注解 @SpringBootApplication,这个注解是对三个注解进行了封装,分别是:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
- 其中 @EnableAutoConfiguration 是实现自动化配置的核心注解。该注解通过 @Import 注解导入对应的配置选择器。
选择器内部就是读取了该项目和该项目引用的 Jar 包的的 classpath 路径下 META-INF/spring.factories 文件(这是boot2的文件名,boot3改为*.imports)中的所配置的类的全类名。
在这些配置类中所定义的 Bean 会根据条件注解所指定的条件来决定是否需要将其导入到 Spring 容器中。
这么解释呢?RedisTemplate这个类大家都熟悉,在springspring.factories 文件的全类名的代码是这样子的

引用依赖之后程序启动前会判断是否有RedisOperations这个类对应字节码,如果有执行下面代码,判断当前环境是否存在RedisTemplate这个bean,如果存在就不加载,没有执行下面代码返回RedisTemplate对象并注入Spring容器中。
好了今天就到这里