1. Spring中的bean为什么要设计成单例的
- 提升性能,减少新生成实例的消耗
- 减少垃圾回收,因为不会有大量bean,需要回收的对象也少了
- 可以从缓存中快速获取bean,因为单例bean除了第一次操作外,其余都是从缓存中获取的,所以比较快
- 但是有状态的对象,在并发环境下线程不安全。关于对象是否有状态,简单一句话:对象中有实例属性,有存储数据的能力,就是有状态的。比如对象定义了变量int a = 0;一般我们就认为是有状态的。
2. 既然Spring默认bean是单例的,那么spring如何确保线程安全
Spring利用ThreadLocal来解决
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。
ThreadLocal的机制:
每个Thread线程内部都有一个Map。
Map里面存储线程本地对象(key)和线程的变量副本(value)
但是,Thread内部的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。
所以对于不同的线程,每次获取副本值时,别的线程并不能获取到当前线程的副本值,形成了副本的隔离,互不干扰。
3. Spring事务传播机制
多个事务方法相互调用的时候,事务在这些方法之间是如何传播的。通俗讲就是一个包含事务的方法调用另外一个包含事务的方法,在调用的时候是新启动一个事务还是说不用事务等等。主要包含几种机制:
- REQUIRED: 默认,当前没有事务就启动一个事务,当前存在事务就加入这个事务
- REQUIRED_NEW: 创建一个新的事务,如果当前存在事务就挂起该事务
- NEVER: 不使用事务,如果当前存在事务,则抛出异常
- NESTED: 内嵌事务,在当前事务里内嵌一个事务执行
- NOT_SUPPORTED: 非事务方式执行,如果当前存在事务就挂起该事务
- MANDATORY: 当前存在事务,加入该事务,当前不存在事务,抛出异常
- SUPPORTS: 当前存在事务,则加入事务,当前不存在事务,则以非事务方式执行
4. Spring事务实现原理是什么
使用Spring框架,有两种事务的实现方式,一种是编程式事务,也就是我们自己写代码去做事务的控制,是基于TransactionTemplate的。另外一种就是声明式事务,也就是注解的方式。通过@Transactional注解。
开发中基本上都是使用注解的方法,添加完注解,事务的自动提交功能就会关闭,由spring框架来控制事务的提交或者回滚。
实现原理的话,还是基于AOP,当方法或者类添加了@Transactional注解后,spring会基于jdk或者cglib动态代理生成一个代理对象,如果有事务处理,那么会先把事务的自动提交给关闭,然后执行具体的业务逻辑,执行正常,那么代理逻辑就执行提交,如果出现异常,那么直接进行回滚。
5. Spring事务什么时候会失效
- 入口方法没加@Transactional事务注解
- 类没有被spring容器管理
- 方法不是public的,生成不了代理方法
- 自身调用,也就是没有用spring生成的bean来调用
- 异常被手动捕获