Spring源码-相关问题

一、Spring延迟加载的实现?

Spring容器在调用AbstractApplicationContext的refresh方法时调用finishBeanFactoryInitialization方法时会将非延迟加载的bean进行创建并缓存。而设置了属性lazy-init="true" 那么启动容器将不会创建该bean放置缓存池

二、Spring是如何解决循环依赖的问题?

a、单例对象缓存

b、早期引用缓存

预先暴露早期引用缓存,第二次拿到的是上一次的早期引用,当前这次者创建完成,上一次将早期引用移除,并把自己的实例放入单例池中,同时将对象工厂移除

c、对象工厂缓存

三、Spring的BeanFactory和FactoryBean的区别?

a、BeanFactory:主要负责bean的创建,初始化,查询,维护bean之间的依赖关系

b、FactoryBean:是一个bean,也是由BeanFactory管理,只是它是一个特殊的bean,类似于工厂方法,能够生成相应的实例

      主要标识是在bean名称上以&区分,我们在通过bean工厂生成相应的实例时,要么生成的bean是它自己,要么是它生产的实例。

四、Spring的初始化和实例化的区别

    a、实例化: 实例化的过程是一个创建bean的过程,即调用bean的构造函数,单例的bean放入单例池中。

    b、初始化:初始化的过程是一个赋值的过程,即调用bean的Setter方法,设置bean的属性。

五、Spring的注解@Service @Component @Repository @Controller的工作原理

六、注解@Required,@Autowired的工作原理

7、Spring中aop的实现原理

首先要明白几个组件的概念:Pointcut,Advice,Advisor,Advised,ProxyFactory

a、Pointcut:就是所谓的切点,个人理解就是连接点JoinPoint的集合

b、Advice:从字面意思上理解就是建议,个人理解就是程序在执行一段代码时向aop框架询问,有什么好的建议?其实就是我们在目标执行点要织入的代码。

aop中存在5个advice:before,around,after,afterReturning,afterThrowing

那么他们在一切面中的执行顺序是什么呢:

   在不出现异常的情况下1):around --》before --〉around --》after --》afterReturning

   出现异常的情况下2):around --》before --》after --》afterReturning

如果不同切面呢,执行顺序又是什么呢?这个时候是不确定的

如果要保证有序,可以加入注解@Order 指定执行顺序,order值越小越先执行,反之越厚。

c、Advisor:顾名思义就是顾问的意思,Advice和Pointcut的集合,程序需要知道在哪鞋地方织入哪些代码

d、Advised:已建议过的,主要通过它调用代理工程来生成相应的Proxy,主要的子类是AdvisedSupport(实现了Proxyconfig)

e、ProxyFactory:生成AopProxy,跟proxy-target-class来决定是否使用jdk还是cglib

这个过程其实就是利用Spring的BeanPostProcess后置处理来生成代理,并将生成bean注册到容器中。其中创建代理类的主要的类AbstractAutoProxyCreator

8、Spring事务的工作原理

a、事务的隔离级别

 1)读未提交:

顾名思义就是,就是可以读取到未提交的内容,查询时时不加锁的,在这种情况下可能产生“脏读”,“不可重复读”,“幻读”

脏读:事务A,开启事务A往表里写入一条数据,此时出现异常回滚,而事务B在事务A写入数据的时候,读取表的数据,这时读取到的数据就是脏数据。

不可重复读:以上面为例,由写入数据改为修改数据,如果事务B再次去读取数据,发现数据也是一样,甚至少了,此时出现不可重复读。

幻读:以上面为例,如果此时事务B再次去读取数据变多了,此时出现幻读

 2)读提交(使用快照读)

只能读取到已经提交到的内容,这里实现的主要是快照读,但是在这种情况下时会出现“不可重复读”,“幻读”问题,

那为什么这里就能解决脏读问题呢?

首先我们先来看一下“快照读”,“当前读”的概念:

“快照读”:读取的是数据的可见版本(可能是过期的数据),不用加锁。

使用的是历史版本,如果使用历史版本去查询数据,就可能出现不可重复读的问题。

“当前读”:每次读取的都是数据的最新版本(update,delete,insert),并且当前读返回的记录都会加上锁,保证其他事务不会再并发的修改这条记录

举个例子:

事务A ,事务B,当事务A开启同时事务B也开启,当事务B查询条件是5去查询一条数据,当时没有提交事务,此时A事务修改了满足A事务的查询条件的一条数据为6并提交了事务,此时事务A再一次查询时发现数据跟上一次查询的一致,则就出现了不能重复读的问题

 3)可重复读(解决update带来的问题)

专门针对不可重复读产生的问题而设置出来的隔离级别,它可以优先的避免”不可重复读“带来的问题,在这个级别下,普通查询也是使用的快照读,唯一的区别是在这个级别下,事务开启就不可以“修改操作(update)”,而”不可重复读”就恰恰在这里两次读之间进行了数据的修改操作导致的查询的数据不一致,虽然可以避免“不可重复读”但是不能避免“幻读”,因为“幻读”是在“插入或删除操作”产生的。

举个例子:我们修改一下上面的例子

事务A ,事务B,当事务A开启同时事务B也开启,当事务B查询条件是5去查询一条数据,当时没有提交事务,此时A事务写入(或删除)一条满足B事务条件的数据,满足A事务的查询条件的一条数据为6并提交了事务,此时事务A再一次查询时发现数据跟上一次查询的一致,则出现了幻读。

 4) 串行化(解决insert,delete带来的问题)

这是数据库最高的隔离级别,在这种级别下事务一个个的有顺序的执行,但是效率极差

b、事务的传播机制的理解

1)PROPAGATION_REQUIRED(required): 支持当前事务,没有就会创建一个(事务存在/事务不存在)

2)PROPAGATION_SUPPORTS:支持当前事务,没有则以非事务的方式执行(事务已经存在)

3)PROPAGATION_MANDATORY:必须在由事务的情况下执行,没有则抛出异常。

4)PROPAGATION_REQUIRES_NEW:如果存在事务则将该事务挂起,不存在就会创建一个新的事物。

如果内层事务出现异常,则回滚,同时如果被外层事务感知将也回滚。

5)PROPAGATION_NOT_SUPPORTS:不支持事务,如果存在事务则将事务挂起,以非事务的方式执行。

6)  PROPAGATION_NEVER: 不支持事务,存在事务将会抛出异常。

7)PROPAGATION_NESTED:

如果存在事务就以嵌套事务执行,嵌套事务异常不会影响到外层的事物,如果不在事务,就会创建一个新的事务执行。

注意:嵌套事务是一个非常重要的概念,内层事务依赖外层事务,内层事务失败将不会影响到外层事务的回滚,内层事务只回滚 到保存点,外层事务的失败将影响到整个事务的回滚,内层事务的提交依赖外层事务的提交。 

下面是执行的大致流程:

  首先先获取事务属性,比如存在注解@Transactional注解,将存在该注解的类中的方法解析成事务属性TransactionAttribute,根据事务属性获取事务到具体的事务平台管理器,同时创建唯一的事务标识,如果事务属性不为空,那么根据需要创建事务信息,那么如何生成相应的事务信息呢?调用事务同一管理器管理生成事务状态对象,调用AbstractPlatformTransactionManager中的getTransaction方法生成,这个方法是处理事务传播机制最重要的一个方法,首先调用doGetTransaction方法,这个方法是抽象方法,由不同的厂商提供,我们可以先看下datasource是怎么生成的?

如果此时bean定义是空的,将创建默认的,根据事务对象transaction来判断当前事务是否存在,判断的条件是根据事务对象DataSourceTransactionObject是否持有链接持有者,如果存在则根据不同的是已经存在的事务的传播机制来返回事务状态对象。

我们从源码的角度看下不同的事物属性的传播机制:

  • PROPAGATION_REQUIRED  ---> PROPAGATION_REQUIRED:

可以看到,这个是个时候判断事务是否存在改走的分支,

可以看到在事务传播属性为这3种时都会创建新的事务并开启事务,此时事务的状态DefaultTransactionStatus中的newTransaction为true,newSynchronization为true,由于事务未激活可得到actualNewSynchronization为true,当传播到PROPAGATION_REQUIRED的方法时,则有actualNewSynchronization此时时false,当执行完目标方法后,不管是否出现异常,都会恢复到上一个事务

 

最后提交事务时根据老得是事务状态来提交。

 

  • PROPAGATION_REQUIRES_NEW 

这个属性的意思:

新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作。如果存在事务则将之前的事务挂起,同时新建一个事务DefaultTransactionStatus,属性actualNewSynchronization为false,属性newTransaction为true

如果出现异常类则直接回滚,将事务状态标记为完成,并恢复原来的事务状态

恢复同步器,恢复挂起的资源,最后以外层事务提交。

  • PROPAGATION_REQUIRES_NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值