Spring整体架构知识构建

13 篇文章 0 订阅

一、Spring两大核心

1、IOC

  • IOC其实它是一种思想,“控制反转”(官方解释),其实这种思想就是 将原本在我们自己写的程序里面去创建对象的权利,交给Spring框架来管理
  • IOC容器是Spring 用来实现Ioc的载体,Ioc容器实际上就是Map的结构,里面存放的是各种对象
  • IOC容器就像一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件 / 注解,完全不用考虑对象是怎么配置出来的。(典型的工厂模式)

2、AOP

  • AOP:面向切面编程(说实话,直接这么说是一脸懵逼的),就是将那些与业务无关的,但是又是这个业务模块所共同调用的逻辑对吧,我们就把他们抽取出来,自己封装起来,统一调用。这样极大程度的减少了重复代码的书写,并且降低了系统的耦合度,利于扩展和维护。(典型的应用就是一些日志管理呀,比如说我想要将调用的每一个controller知道他的调用时间,并且入库,对吧,这时候我们写个切面是很好的处理)
  • 核心是动态代理,若果代理的对象实现了某个接口,那么spring AOP就会使用JDK动态代理,去创建对象。对于没有实现接口的对象,spring aop会使用Cglib动态代理生成一个被代理的子类作为代理对象
  • AspectJ AOP:编译时增强,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
  • AOP切面是一个实现举例
    在这里插入图片描述

二、Spring bean

1、Bean的作用域

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的
  • prototype : 每次请求都会创建一个新的 bean 实例。
  • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
  • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

2、线程安全问题

  • 多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题
  • 一般情况下,我们常用的 ControllerServiceDao 这些 Bean 是无状态的无状态的 Bean 不能保存数据,因此是线程安全的。
  • 解决办法:
    • 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
    • 改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。

3、Bean的生命周期

  • Bean 容器(IOC容器)首先找到配置文件的中的Spring Bean的定义
  • Bean 容器利用反射来创建Bean的一个实例
  • 如果涉及到一些属性,那么就利用set()方法来设置一些属性值
  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。
  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
  • 如果实现了其他 *.Aware接口,就调用相应的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

在这里插入图片描述
在这里插入图片描述

4、循环依赖问题⭐

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

如果是我们自己写的,就会无限创建对象,(类似于死循环),导致内存占满报错,那么Spring是如何解决这种情况呢?

Java中的循环依赖分两种,一种是构造器的循环依赖,另一种是属性的循环依赖
Spring解决的循环依赖就是指属性的循环依赖

首先我们先介绍一下Spring的三级缓存:

  • singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
  • earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例
  • singletonFactories 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。

ps:盗用一张图(发生了什么??):
在这里插入图片描述

三、Spring 中的事务问题

其实,在我的理解里面Spring的事务是跟数据库保持一致的,如果我们选择的数据库它不支持事务(比如myisam),那么我们Spring里面的事务就不会起到作用。

1、四种事务特征(ACID)

  • 原子性:强调事务的不可分割
  • 一致性:事务的执行前后,数据的完整性保持一致
  • 隔离性:一个事务执行过程中,不受其他事务的干扰
  • 持久性:事务一旦执行结束,数据就持久到数据库,不会因为数据库宕机而发生数据修改失败等

2、五种隔离级别(比数据库多了一个默认级别)

  • TransactionDefinition.ISOLATION_DEFAULT:使用数据库默认的事务隔离级别
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

3、七种传播行为

  • 支持当前事务
    • PROPAGATION_REQUIRED :默认的事务传播行为,如果当前存在事务,则加入该事务,如果当时没有事务,则创建一个新事物。
    • PROPAGATION_SUPPORTS:如果当前事务存在就加入该事务,如果不存在,则以非事务的方式运行
    • PROPAGATION_MANDATORY:如果当前事务存在就加入,不存在就抛出异常
  • 不支持当前事务
    • PROPAGATION_REQUIRES_NEW :创建一个新的事务,如果存在当前的事务就挂起这个事务
    • PROPAGATION_NOT_SUPPORTED:以非事务的方式运行,如果存在当前事务就挂起
    • PROPAGATION_NEVER:以非事务的方式运行,如果存在当前事务就抛出异常
  • 其他
    • PROPAGATION_NESTED :嵌套事务,如果当前存在事务则在嵌套事务中执行,如果没有就以PROPAGATION_REQUIRED方式运行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值