spring核心知识点
说一下spring ioc的理解,原理和实现
总
ioc:控制反转。原来的对象是由使用者来控制的,有了spring,就直接把整个对象交给spring来帮我们管理。
DI:依赖注入。把对应的属性的值注入到具体的对象中,@autowired,populatebean完成属性值得注入
容器:存储对象,使用map结构存储,在spring中一般存在三级缓存,singletonOBjects存放文章的bean对象,在整个bean的生命周期中,从创建到使用到销毁都是由容器来管理的。
分
IOC和DI
举一个例子:有车,底盘,轮胎,在没有spring之前,我们相对这样的整体架构进行设计,一个常用的方法就是通过构造器注入,我们在创建一个底盘的时候,需要new一个轮子的对象,把这个对象的尺寸,材料设置好后,通过底盘的构造器放入底盘中。同样,我们在最终创建一个车的时候,需要先创建一个轮胎对象,在创建一个底盘对象,最后才能创建出我们想要的车的对象。然后spring就帮我解决了这样的而问题,你可以直接去创建一个车的对象,而具体的底盘和轮胎的对象注入,由spring自己来进行,你只需要在开始创建这样的bean就行了
这里的ioc,就像是一个工厂
所以我们在项目中经常回遇到bean找不到报错的问题,应为spring是只是帮你去把你创建的bean给找出来,所以在项目运行的时候需要有一个初始化好的bean。可以通过xml去定义一个bean,也可以通过注解@bean,@controller等等去定义一个bean
推荐文章:Spring IoC有什么好处呢? - Mingqi的回答 - 知乎 https://www.zhihu.com/question/23277575/answer/169698662
容器
- 首先开始创建一个容器(beanFactory , DefaultListableBeanFactory),然后想bean工厂中设置一些参数(beanPostProcessor,Aware接口的子类)等等属性
- 加载解析bean对象,准备要创建的bean对象的定义对象beanDefintion(XML或者注解)
- beanFactoryPostProcessor的处理,在此处可以自定义扩展,PlaceHolderConfigurSupport,ConfigurationClassPostProcessor
- BeanPostProcessor的注册功能,方便后续对bean’对象完成具体的扩展功能
- 通过反射的方式将BeanDefintion对象实例化成具体的bean对象
- bean对象的初始化过程(填充属性,调用aware接口子类的方法,调用BeanPostProcesor的前置处理方法,调用init-method方法,调用BeanPostProcessor的后置处理方法)
- 生成完整的bean对象,通过getBean方法可以直接获取
- 销毁,(调用DisposableBean的destory方法,调用自定义销毁方法)
- 结束
实际应用
通过实现BeanPostProcessor接口,对beanFactory的创建过程进行整体修改
对bean的扩展,在项目中使用@value注入yml的属性,现在在分布式情况下,相对这个@value注入自定义扩展(比如添加前缀或者从特定位置读取默认值)
谈一下spring IOC的底层实现
总
createBeanFactory,getBean,doGetBean,doCreatBean,creatBeanInstance(getDeclaredConstructor,newinstance),populateBean,initializingBean
(备注:加do的方法都是主要业务逻辑方法)
分
- 先通过creatBeanFactory创建出一个bean工厂(DefaultListableBeanFactory)
- 开始循环创建对象,因为容器中的bean默认都是单例的,所以优先通过getBean,doGetBean从容器中查找,找不到的话
- 通过createBean,doCreateBean方法,以反射的放射创建对象,一般情况下使用无参的构造方法(getDeclaredConstructor,newInstance)
- 进行对象的属性填充populateBean
- 进行其他的初始化操作(initializingBean)
描述一下bena的生命周期
总
分
- 实例化bean:反射的方式生成对象
- 填充bean的属性:populateBean(),循环依赖的问题(三级缓存)
- 调用aware接口相关的方法:invokeAwareMethod(完成BeanName,BeanFactory,BeanClassLoader对象的属性设置)
- 调用BeanPostProcessor中的前置处理方法:使用比较多的有(ApplicationContextPostProcessor,设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver)
- 调用initmethod方法:invokeInitmethod(),判断是否实现了initializingBean接口,如果有,调用afterPropertiesSet方法,没有就不调用
- 调用BeanPostProcessor的后置处理方法:spring中的AOP就是在此处实习的,AbstractAutoProxyCreator。
- 注册Destuction相关的回调接口:(钩子函数)
- 获取到完成bean对象,可以通过getBean的方法进行对象的获取
- 销毁
- 判断是否实现了DisproableBean接口
- 调用destoryMethod的方法
Spring是如何解决循环依赖问题
核心思想:提前暴露对象,把不完整的对象注入
总
使用三级缓存,提前暴露bean的对象,也就是把实例化和初始化分开操作,把不完整的对象注入
分
假如A和B对象循环依赖
- 先创建A对象,实例化A对象,此时A对象中的B属性为空,开始填充属性B
- 从容器中查找B对象,如果找到了,直接赋值不存在循环依赖问题(但是现在A和B对象循环依赖),没有找到直接创建B对象
- 实例化B对象,此时B对象中的A属性为空,填充A属性
- 从容器中查找A对象,找不到,直接创建
在spring中,第四步的A对象是存在的,只不过此时的A对象不是一个完整的状态,只完成了实例化但是未完成初始化,如果在程序调用过程中,拥有了某个对象的引用,能否再后期给他完成赋值操作,可以优先把非完整的对象优先赋值,等待后续操作来完成赋值,相当于提前暴露了某个不完整的对象的引用。
所以解决循环依赖问题的关键就是,把实例化和初始化分开操作,当所有的对象都实例化和初始化操作后,还是要把完整的对象放到容器中,此时在容器中存在对象的几个状态:未完成实例化,完成实例化但为完成初始化,完整状态。因为都在容器中,所以要使用不同的map结构来进行存储,此时就有了一级缓存和二级缓存,如果一级缓存中有了,那么耳机缓存中就不会存在同名的对象,因为他们的查找顺序是1,2,3级缓存的方式进行查找的。在一级缓存中存放的是完整对象,二级缓存中存放的是非完整对象
为什么需要三级缓存?三级缓存的value类型是ObjectFactory,是一个函数式接口,存在的意义是保证整个容器的运行过程中同名的bean对象只能有一个。
如果一个对象需要被代理,或者需要生成代理对象,那么要不要优先生成一个普通对象?需要,在源码中调用的代理方法(BeanPostProcessor)的时候需要传入一个bean对象
普通对象和代理对象是不能同时出现在容器中,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,是没有办法确定什么时候对象被使用,所以就要求当某个对象被调用的时候,优先判断此对象是否需要被代理,类似于一种回调机制的实现,因此传入lambda表达式的时候,可以通过lambda表达式来执行对象的覆盖过程,getEarlyBeanReference()
因此,所有的bean对象在创建的时候都要优先放到三级缓存中,在后续的使用过程中,如果需要被代理则返回代理对象,如果不需要被代理,则直接返回普通对象
三级缓存的放置时间和删除时间
三级缓存:createBeanInstance之后,addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象,同时删除三级缓存getSingleton
一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingleton
BeanFactory与FactoryBean有什么区别
相同点:都是创建bean对象
不同点:使用benaFactory创建对象的时候,必须要遵循严格的生命周期流程,太复杂了。如果想要简单的自定义某个对象的创建,同时创建完成的对象想交给spring来管理,那么就需要实习FactoryBean接口
isSingleton:创建的bean是否为单例bean
getObjectType:获取返回对象的类型
getObjet:自定义创建对象的过程(new,反射,动态代理)
Spring中用的到的设计模式
单例模式:bean默认都是单例的
原型模式:指定作用域为prototype
工厂模式:BeanFactory
模板方法:postProcessBeanFactory,onRefresh,initPropertyValue
策略模式:XmlBeanDefinitionReader,PropertiesBeanDefinitionReader
观察者模式:listener,event,multicast
适配器模式:Adapter
装饰者模式:BeanWrapper
责任链模式:使用aop的时候回先生成一个拦截器链
代理模式:动态代理
委托者模式:delegate
Spring中AOP的底层实现原理
总
AOP是ioc的一个扩展功能,现有的ioc,在有的aop,只是在ioc的整个流程中新增的一个扩展点而已(BeanPostProcessor),底层是用的动态代理实现的,常用的应用场景油自定义注解等等
分
在bean的创建过程中,可以在BeanPostProcessor的后置处理方法实习aop
- 代理对象的创建过程(advice,切面(@around,@After),切点(@pointCut))
- 通过jdk或者cglib的方式来生成代理对象
- 在执行方法调用的时候,会调用生成的字节码文件,直接找到DynamicAdvisoredIntercepto类中的intercept方法,从此方法开始执行
- 根据之前定义好的通知来生成拦截器链
- 从拦截器链中依次获取每一个通知开始进行执行,在执行的过程中,为了方便找到下一个通知是哪个,会有一个InvocationInterceptor的对象,找的的时候从-1的位置依次开始查找并执行的
Spring事务的传播机制
https://blog.csdn.net/qq_26323323/article/details/81908955
https://zhuanlan.zhihu.com/p/360375611
- Propagation.REQUIRED:如果有事务则加入事务,如果没有事务,则创建一个新的(默认值)
- Propagation.NOT_SUPPORTED:不为当前方法开启事务,相当于没有事务
- Propagation.REQUIES_NEW:不管事务是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务
Spring的事务是如何回滚的
总
spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑。正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑
分
mysql中事务的实现机制(下图左):
具体还设计到了myql的MVCC机制(一致性)、锁(隔离性)、redo log(持久性)、undolog(原子性)
推荐文章:https://blog.csdn.net/weixin_33560311/article/details/113138290
AOP实现事务的机制(下图右):
- 先做准备工作,解析各个方法上事务的相关属性,根据具体的属性来判断是否开启新的事务
- 当需要开启的时候,获取数据库连接(这里也是用的连接池),关闭自动提交功能,开启事务
- 执行具体的sql逻辑操作
- 在操作过程中,如果执行失败了,那么会通过completeTransactionThrowing看来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是先获取连接对象,通过连接对象来回滚
- 如果执行过程顺利完成,通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实习的,实现的时候也是要获取连接,通过连接对象提交(所以获取的链接对象要保持一致,currentConnection)
- 当前事务执行完毕后需要清楚相关的事务信息cleanupTransactionInfo(断开连接,释放资源)
深入的话,还需要知道TransactionInfo,TransactionStatus
spring事务传播
一共有七种传播特性:
Required、Requies_new 、nested、support、not_support、never、mandatory
事务名称 | 解析 |
---|---|
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED) | 支持当前事务:如果没有事务会创建一个新的事务 |
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS) | 支持当前事务:如果没有事务的话以非事务方式执行 |
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY) | 支持当前事务:如果没有事务抛出异常 |
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW) | 创建一个新的事务并挂起当前事务 |
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED) | 如果当前存在事务则将当前事务挂起,以无事务方式运行。外层没有事务,以无事务方式运行 |
NEVER(TransactionDefinition.PROPAGATION_NEVER) | 如果存在事务则抛出异常 |
NESTED(TransactionDefinition.PROPAGATION_NESTED) | 嵌套事务:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
A方法调用B方法,AB都有自己的事务,并且传播特性不同,那么A如果有异常,B怎么办,B如果有异常,A怎么办
总
事务的传播特性是在不同事务的嵌套方法调用中,事务应该怎么进行?是用一个事务(用哪个事务?),还是不同的事务?当出现异常的时候是全部回滚,还是提交,这不同事务之间的相关影响的解决。
分
1.先说事务的不同分类,可以分为三类,支持当前事务,不支持当前事务,嵌套事务
2.如果外层方法是required,内层方法是:required,requireds_new,nested
3.如果外层方法是requireds_new,内层方法是:required,requireds_new,nested
4.如果外层方法是nested,内层方法是:required,requireds_new,nested
注意:新事物和子事务的区别:
新事物:外层事务回滚,不影响新事物;新事物的回滚,不影响外层事务,除非外层事务又异常处理,代码回滚新事务
子事务:外层事务回滚,子事务也会回滚;子事物的回滚,不影响外层事务,除非外层事务又异常处理,代码回滚子事务
外层 | 内层 | 结果(外层有事务) | 结果(外层没有事务) | 原因 | 外层有事务时出现异常 |
---|---|---|---|---|---|
REQUIRED | REQUIRED,SUPPORTS,MANDATORY | 使用外层事务 | 使用自己的事务逻辑(创建新事物,无事务运行或者抛异常) | 整体回滚 | |
REQUIRES_NEW,NOT_SUPPORTED,NEVER | 使用自己的事务逻辑(外层事务挂起后创建新的事务,外层事务挂起后以无事务方式运行或者抛异常) | 使用自己的事务逻辑(创建新事物,无事务运行或者抛异常) | 这种有可能会造成死锁,因为会影响上一个事务,如果上一个事务已经表锁了,这个事务又操作表,但获取不到资源 | 外层事务回滚,不影响新事物 | |
NESTED | 使用自己的事务逻辑(外层事务挂起后创建子事务) | 使用自己的事务逻辑(创建子事务) | 外层事务回滚,子事务也会回滚 | ||
在spring中,主要是在beanPostProcessor中进行事务的处理,事务都会生成一个InfrastructureAdvisorAutoProxyCreator对象。
getAdviceAndAdvisorsForBean(获取事务通知的方法)
creatProxy,创建代理对象
走代理(实现接口走Proxy或者没有实现接口cglib)
执行invoke方法,获取拦截器的链(TransactionInterceptor)
invokeWithTransaction,获取事务上的注解属性(rollbackRules,quailfer,descriptor,propagationBehavior,isolationLevel,timeout,readonly,name)
creatTransactionIfNessary,从当前线程(ThreadLocal)中获取事务(TransactionSynchronizationManager.getResource(obtainDataSource()))
- 当前线程没有事务,就开始这个事务
- dobegin,把这个事务绑定到当前线程中,把连接的自动提交关闭,把当前事务设置为活跃的事务
- 执行事务中的方法
事务中的方法还有一个事务,指定方法
获取拦截器中的TransactionInterceptor
invokeWithTransaction,获取事务上的注解属性
creatTransactionIfNessary,从当前线程中获取事务
这个时候当前线程已经有事务
handlerExistingTransaction,处理存在的事务
如果这个事务(difintion.getPropagationBehavior)是NEVER的话,直接抛出异常
如果事务是NOT_SUPPORTED的话,当前事务挂起
如果事务是REQUIRES_NEW的话,开始一个新的事务(dobegin)
如果是NESTED,开始子事务
执行事务中的方法,如果出现异常,则事务回滚(doRollback)