Spring
Spring 框架中的单例 Bean 是线程安全的吗?
Spring 框架中的 bean 是单例的吗?

- singleton:bean 在 Spring Ioc 容器中只有一个实例
- prototype:一个 bean 的定义可以有多个实例
ANS:
不是线程安全的。Spring 框架中有一个@Scope
注解,默认的值就是 singleton,单例的。因为一般在 Spring 的 bean 中注入的都是无状态对象,所以是线程安全的。但是如果 bean 中定义了可修改的成员变量,就要考虑线程安全问题,可以使用和加锁解决。
什么是 AOP,项目中有没有使用到 AOP?
常见的 AOP 使用场景:
- 记录操作日志
- 缓存处理
- Spring 中内置的事务处理
使用 AOP 中的环绕通知+切点表达式实现了系统操作日志。使用环绕通知是为了记录当前方法是否成功执行,以及统计方法的执行时间。也就是需要方法在成功和异常两种情况下都能成功执行。
Spring 中的事务是如何实现的?
声明式事务管理:声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
ANS:
其本质是通过 AOP 功能,对方法前后进行拦截,在执行方法前开启事务,方法执行后根据方法执行情况提交或者回滚事务。
Spring 中事务失效的场景
- 异常捕获处理
- 抛出检查异常
- 非 public 方法
异常捕获处理

原因:
:::info
事务通知只有捕获到了目标抛出的异常,才能进行回滚处理。如果目标自己处理异常,那么事务将无法知悉。
:::
解决:
:::info
在 catch 块添加 throw new RuntimeException(e)抛出。
:::
抛出检查异常

原因:
:::info
Spring 默认只会回滚非检查异常(RuntimeException 及其子类)
:::
解决:
:::info
配置 rollbackFor 属性
@Transactionnal(rollbackFor=Exception.class)
(所有异常都回滚)
:::
非 public 方法导致的事务失效

原因:
:::info
Spring 为方法创建代理、添加事务通知,前提条件该方法必须是 public 方法
:::
解决:
:::info
改为 public 方法
:::
Bean 的生命周期


bean 的循环依赖(循环依赖)
产生过程:

三级缓存:

如果想打破循环依赖,可以用二级缓存。

:::info
加载 A 时需要注入 B,B 不存在,此时实例化 B 并初始化,然后 B 被放进二级缓存中,A 作为半成品,也是被放进二级缓存中。加载 B 时就可以直接从二级缓存中获取 A,注入 A,B 创建成功,存储到单例池中,随后加载 A 时可以直接注入 B 对象,这样就都完成了加载。
:::
代理对象需要使用三级缓存:

构造方法出现了循环依赖怎么办?

SpringMVC
SpringMVC 的执行流程知道吗?

- 用户发送出请求到前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping(处理器映射器)
- HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
- DispatcherServlet调用HandlerAdapter(处理器适配器)
- HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
- 方法上添加了@ResponseBody
- 通过HttpMessageConverter来返回结果转换为JSON并响应
SpringBoot 自动配置原理

- 在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:
- @SpringBootConfiguration- @EnableAutoConfiguration
- @ComponentScan
- 其中@EnableAutoConfiguration是实现自动化配置的核心注解。该注解通过@Import注解导入对应的配置选择器。
内部就是读取了该项目和该项目引用的Jar包的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。
- 条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有Bean放入spring容器中使用。
Spring 框架常见的注解(SpringMVC、Spring、Spring Boot)
Spring 常见的注解
注解 | 说明 |
---|---|
@Component、@Controller、@Service、@Repository | 使用在类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Configuration | 指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器时要扫描的包 |
@Bean | 使用在方法上,标注将该方法的返回值存储到Spring容器中 |
@Import | 使用@Import导入的类会被Spring加载到IOC容器中 |
@Aspect、@Before、@After、@Around、@Pointcut | 用于切面编程(AOP) |
@Scope | 标注Bean的作用范围 |
SpringMVC 常见的注解
注解 | 说明 |
---|---|
@RequestMapping | 用于映射请求路径, 可以定义在类上和方法上。用于类上,则表示类中的所有的方法都是以该地址作为父路径 |
@RequestBody | 注解实现接收http请求的json数据, 将json转换为java对象 |
@RequestParam | 指定请求参数的名称 |
@PathVariable | 从请求路径下中获取请求参数(/user/{id}), 传递给方法的形式参数 |
@ResponseBody | 注解实现将controller方法返回对象转化为json对象响应给客户端 |
@RequestHeader | 获取指定的请求头数据 |
@RestController | @Controller + @ResponseBody |
SpringBoot 常见注解
注解 | 说明 |
---|---|
@SpringBootConfiguration | 组合了-@Configuration注解, 实现配置文件的功能 |
@EnableAutoConfiguration | 打开自动配置的功能,也可以关闭某个自动配置的选 |
@ComponentScan | Spring组件扫描 |
MyBatis 执行流程

①读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
② 构造会话工厂SqlSessionFactory
③ 会话工厂创建SqlSession对象(包含了执行SQL语句的所有方法)
④ 操作数据库的接口,Executor执行器,同时负责查询缓存的维护
⑤ Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
⑥ 输入参数映射
⑦ 输出结果映射
MyBatis 延迟加载使用及原理

- 使用CGLIB创建目标对象的代理对象
- 当调用目标方法user.getOrderList()时,进入拦截器invoke方法,发现user.getOrderList()是null值,执行sql查询order列表
- 把order查询上来,然后调用user.setOrderList(List orderList),接着完成user.getOrderList()方法的调用

MyBatis 一级、二级缓存

一级缓存
一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存, 其存储作用域为 Session, 当Session进行flush或close之后, 该Session中的所有Cache就将清空,默认打开一级缓存。
二级缓存
二级缓存是基于namespace和mapper的作用域起作用的, 不是依赖于SQL session,默认也是采用PerpetualCache,HashMap存储


注意事项:
- 对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存 Namespaces)进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear
- 二级缓存需要缓存的数据实现 Serializable 接口
- 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
ANS
- 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存, 其存储作用域为 Session, 当Session进行flush或 close之后, 该Session中的所有Cache就将清空,默认打开一级缓存
- 二级缓存是基于namespace和mapper的作用域起作用的, 不是依赖于SQL session, 默认也是采用 PerpetualCache, HashMap 存储。需要单独开启, 一个是核心配置, 一个是mapper映射文件