生命周期
1. 加载配置文件或者通过配置文件扫描java文件
2. 然后会将每个java文件的beanClass,是否是Lazy,是否是单例(Single),多例(prototype)放到一个BeanDefinintion对象中,然后将BeanDefinition对象放入map中
3. 循环遍历BeanDefinition对象然后对beanClass进行实例化操作,属性填充
4. 之后就进入初始化阶段,在进行初始化阶段的时候可以做一些初始化前和初始化后的一下前置或后置操作,以及赋值spring访问容器中的数据Aware等操作
5. 初始化完成后就进入了正常使用阶段
6. 最后就是销毁阶段
Spring 的 AOP 有哪几种创建代理的方式
spring的AOP目前支持JDK动态代理和Cglib代理,如果目标对象实现了接口,会默认使用JDK动态代理,否则使用cglib动态代理,也可以在配置文件中设置proxy-target-class: true来默认使用cglib动态代理。
两者的区别:
1. jdk动态代理是通过反射机制来实现代理接口的匿名类,在调用具体方法前调用invokeHandle来处理,cglib是fastClass来通过索引值找打具体的方法来执行
2. 目标对象实现了接口,就会默认使用jdk动态代理,否则就会用cglib代理,也可以通过修改配置来达到默认使用cglib
Spring 的4种事务特性(ACID)
原子性,一致性,隔离性,持久性
Spring 的5种事务隔离级别
spring事务隔离级别是基于数据库实现的
DEFAULT, 默认使用数据库的隔离级别
READ_UNCOMMITED, 读未提交的,在事务中读取到其他事务未提交的数据,产生脏读(例如A事务读取到了B事务中的变量为1,但是B事务最后失败回滚了)
READ_COMMITED,读已提交的,在事务中每次都能读取到最新提交的数据,能解决脏读,但会产生不可重复读(例如A事务读取到B事务提交的变量1,然后下个方法或代码读取到了C事务提交的变量2,在一个事务中读到的值是不一样的)
REPEATABLE_READ, 可重复读,在一个事务中每次读取的内容都是一样的,但是会存在幻读(例如原本事务A读到了10条记录,但是另外一个事务B新增了一条并提交事务,此时事务A读到了11条)
Spring 的7种事务传播行为
REQUIRED: 如果当前没有事务就新建一个事务,如果有事务,就加入到这个事务中
REQUIRES_NEW: 会将上文事务挂起,重新开启一个事务,事务提交完成后才会继续上文事务,上文事务回滚,不会影响到新事务
NESTED:嵌套事务,如果上文事务回滚,子事务一定回滚,但是内部子事务单独回滚不会影响外部事务或者其他子事务
SUPPORTS: 支持事务,如果上文没有事务就以非事务执行
NOT_SUPPORTED: 不支持事务,如果上文有事务,上文事务会被挂起,当前方法以非事务执行完后再接着上文事务继续执行。当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。
NEVER: 以非事务执行,如果当前上文有事务,直接报错, 不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。
MANDATORY: 强制事务,如果当前上文没有事务,直接报错
Spring 事务的实现原理
底层采用AOP(动态代理)+ ThreadLocal + try/catch
Spring 怎么解决循环依赖的问题
使用了三级缓存
1. 假如A依赖了B, B又依赖了A
2. 那么在加载是会先判断A是否在缓存中,如果不存在就对A实例化,然后通过构造函数创建bean A,通过ObjectFacotry提前将A暴露出口来
3. 然后A到了数据填充阶段,发现有个B,就判断B是否在缓存,如果不在就对B实例化,然后通过构造函数创建bean B,通过ObjectFactotry提前将B暴露出来
4. 然后B到了数据填充阶段发现有个A,但是在缓存中找到了A,得到了bean A,之后填充属性就完成了