Spring相关知识(一)

289 阅读4分钟

JYM大家好,这里是布洛妮娅, 鸭鸭的更文频道😎,本篇文章是对Spring的一个学习记录和总结!!

一、Spring的优点?

Spring 是一个轻量级应用框架,它提供了 IOC 和 AOP 这两个核心的功能.

它的核心目的是为了简化企业级应用程序的开发,使得开发者只需要关心业务需求,不需要关心 Bean 的管理, 以及通过切面增强功能减少代码的侵入性.

从 Spring 本身的特性来看:

  • 轻量:Spring 是轻量的,基本的版本大约 2MB.
  • IOC/DI:Spring 通过 IOC 容器实现了 Bean 的生命周期的管理,以及通过 DI 实现依赖注入,从而实现了对象依赖的松耦合管理.
  • AOP:Spring 支持面向切面的编程,从而把应用业务逻辑和系统服务分开.
  • MVC框架:Spring MVC 提供了功能更加强大且更加灵活的 Web 框架支持.
  • 事务管理:Spring 通过 AOP 实现了事务的统一管理,对应用开发中的事务处理提供了非常灵活的支持.

二、Spring中事务的传播行为有哪些?

所谓的事务传播行为,就是多个声明了事务的方法相互调用的时候,这个事务应该如何传播. 比如说,methodA()调用 methodB(),两个方法都显示的开启了事务。那么 methodB()是开启一个新事务,还是继续在 methodA()这个事务中执行?就取决于事务的传播行为.

在 Spring 中,定义了 7 种事务传播行为:

  • REQUIRED:默认的 Spring 事物传播级别,如果当前存在事务,则加入这个事务,如果不存在事务,就新建一个事务.
  • REQUIRE_NEW:不管是否存在事务,都会新开一个事务,新老事务相互独立.外部事务抛出异常回滚不会影响内部事务的正常提交.
  • NESTED:如果当前存在事务,则嵌套在当前事务中执行.如果当前没有事务,则新建一个事务,类似REQUIRE_NEW.
  • SUPPORTS:表示支持当前事务,如果当前不存在事务,以非事务的方式执行.
  • NOT_SUPPORTED:表示以非事务的方式来运行,如果当前存在事务,则把当前事务挂起.
  • MANDATORY:强制事务执行,若当前不存在事务,则抛出异常.
  • NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常. Spring 事务传播级别一般不需要定义,默认就是 PROPAGATION_REQUIRED,除非在嵌套事务的情况下需要重点了解.

三、Spring Bean的作用域?

Spring的作用域分为:

  1. singleton:唯一 Bean 实例,Spring 中的 Bean 默认都是单例的。
  2. prototype:每次请求都会创建一个新的 Bean 实例。
  3. request:每一次 HTTP 请求都会产生一个新的 Bean,该 Bean 仅在当前 HTTP request 内有效。
  4. session:每一次 HTTP 请求都会产生一个新的 Bean,该 Bean 仅在当前 HTTP session 内有效。
  5. global-session:全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring 5 已经没有了。Portlet 是能够生成语义代码(如 HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

在开发过程中,对有状态的 Bean 建议使用 Prototype,对无状态建议使用 Singleton

参考资料:一文读懂 Spring Bean 的生命周期

四、Spring中什么样的Bean会存在线程安全问题?

Spring 容器中的 Bean 其实都是根据我们自己写的类来创建的实例。因此,Spring 中的 Bean 是否线程安全, 跟 Spring 容器无关,只是交由 Spring 容器托管而已.

从第三点我们可以知道:

prototype(多例) Bean 每次都会新创建新实例,也就是说线程之间不存在 Bean 共享的问题。因此,多例 Bean 是不存在线程安全问题的.

而单例 Bean 是所有线程共享一个实例,因此,就可能会存在线程安全问题。但是单例 Bean 又分为无状态 Bean 和有状态 Bean。在多线程操作中只会对 Bean 的成员变量进行查询操作,不会修改成员变量的值,这样的 Bean 称之为无状态 Bean。所以,可想而知,无状态的单例 Bean 是不存在线程安全问题的。但是,在多线程操作中如果需要对 Bean 中的成员变量进行数据更新操作,这样的 Bean 称之为有状态Bean,所以,有状态的单例 Bean 就可能存在线程安全问题.

五、如何处理Spring Bean的线程安全的问题?

  1. 将Bean的作用域由Singleton改为Prototype.
  2. 在类中定义ThreadLocal的成员变量,并将需要的可变成员变量保存到ThreadLocal中.

ThreadLocal本身就具备线程隔离的特性,相当于为每个线程提供一个独立的变量副本,每个线程只需要操作自己线程副本变量,从而解决线程安全的问题.

PS:在使用完ThreadLocal后我们应该手动调用它的remove方法,防止发生内存泄露.