一、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、线程安全问题
多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题。
一般情况下,我们常用的 、、 这些 Bean 是无状态的。无状态的 Bean 不能保存数据,因此是线程安全的。
解决办法:
在类中定义一个 成员变量,将需要的可变成员变量保存在 中(推荐的一种方式)。
改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。
3、Bean的生命周期
Bean 容器(IOC容器)首先找到配置文件的中的Spring Bean的定义
Bean 容器利用反射来创建Bean的一个实例
如果涉及到一些属性,那么就利用方法来设置一些属性值
如果 Bean 实现了 接口,调用 方法,传入Bean的名字。
如果 Bean 实现了 接口,调用 方法,传入 对象的实例。
如果实现了其他 接口,就调用相应的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 对象,执行 方法
如果Bean实现了接口,执行方法。
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
如果有和加载这个 Bean的 Spring 容器相关的 对象,执行 方法
当要销毁 Bean 的时候,如果 Bean 实现了 接口,执行 方法。
当要销毁 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、五种隔离级别(比数据库多了一个默认级别)
:使用数据库默认的事务隔离级别
:最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
: 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
3、七种传播行为
支持当前事务
:默认的事务传播行为,如果当前存在事务,则加入该事务,如果当时没有事务,则创建一个新事物。
:如果当前事务存在就加入该事务,如果不存在,则以非事务的方式运行
:如果当前事务存在就加入,不存在就抛出异常
不支持当前事务
:创建一个新的事务,如果存在当前的事务就挂起这个事务
:以非事务的方式运行,如果存在当前事务就挂起
:以非事务的方式运行,如果存在当前事务就抛出异常
其他
:嵌套事务,如果当前存在事务则在嵌套事务中执行,如果没有就以方式运行
------------END-----------
领取专属 10元无门槛券
私享最新 技术干货