# Spring 的 Bean 是线程安全的吗

不是

Spring 容器中的 Bean 默认是 singleton 单例的,所有线程共享一个单例 Bean, 因此是存在资源竞争的;

但在实际开发中,单例 Bean 一般都是以无状态的方式来使用,即线程之间的操作不会对 Bean 的成员执行除查询以外的操作,所以这个 Bean 又可以说是线程安全的。比如:Controller,Service,Dao 等这些 Bean 大多数是无状态的,我们不会对这些 Bean 中的属性进行修改操作,只需要关注方法本身即可;

# 如何保证 Spring 容器中 Bean 是线程安全的

  • 把默认的 singleton 单例的 Bean 改为 prototype 多例的 Bean
  • 在 Bean 对象中避免定义可变的成员变量
  • 如果 Bean 对象中需要定义可变成员变量,将可变成员变量保存在 ThreadLocal 中;

# 什么情况下会触发 Spring 事务回滚

在事务方法发生异常时触发

# 如果事务方法抛出 IOException 是否会触发 Spring 事务回滚

  • 如果采用 Spring 默认的事务回滚规则,它默认是发生 RuntimeException 异常时触发事务回滚,而现在是抛出 IOException 异常,那么不会触发 Spring 事务回滚
  • 如果想触发 IOException 异常事务回滚,需要指定回滚的规则
  • @Transactional(rollbackFor = IOException.class)

# 什么情况下 Spring 事务会失效

  • 同一个 service 中,方法 a 标注事务注解,方法 b 没有标注事务注解 (a 有,b 没有)
  • 同一个 service 中,没有标注事务注解的 b 方法调用标注了事务注解的 a 方法 (无事务)
  • 不同的 Service 中,没有标注事务注解的 b 方法调用标注了事务注解的 a 方法 (有事务)
  • 标注了事务注解的 public 方法,protected 方法,默认无修饰方法,private 方法,final 方法,static 方法 (public 有效,其他均无效)
  • 多线程中的事务 (仅对当前线程有效,异步的新线程无效)

具体情况如下

  • 异常类型错误
  • 方法或类上没有标注 @Transactional
  • 同一类中,方法内部自调用
  • 事务方法不是 public 的
  • 多线程调用
  • 异常被 try...catch
  • 手动抛了别的异常
  • 事务方法所在的 Bean 未被 Spring 容器管理
  • 方法的事务传播类型不支持事务
  • 表的数据库引擎不支持事务,比如 MyISAM 存储引擎不支持事务

# Spring 框架 Bean 的生命周期

  1. 解析 xml 文件配置或者注解的类,得到 BeanDefinition
  2. 通过 BeanDefinition 反射创建 Bean 对象 (实例化 Bean 对象)=-
  3. 对 Bean 对象进行实例填充
  4. 回调实现 Aware 接口的方法,如 BeanNameAware
  5. 调用 BeanPostProcessor 的初始化前方法
  6. 调用 init 初始化方法 (如果有的话)
  7. 调用 BeanPostProcessor 的初始化后方法,此处会进行 AOP
  8. 将创建好的 Bean 对象放入一个 Map 中
  9. 业务中使用 Bean 对象就从 Map 中获取
  10. Spring 容器关闭时调用 DisposableBean 的 destory 方法销毁 Bean 对象
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

KagurazakaAsahi 微信支付

微信支付