【面试】春天事务面试考点吐血整理(建议珍藏)

  

<强>从一个笑话开始

  

问:把大象放冰箱里,分几步?

  

答:三步啊,第,一把冰箱门打开,第二,把大象放进去,第三,把冰箱门带上。

  

问:实现春天事务,分几步?

  

答:三步啊,第一,找出需要事务的方法,第二,把事务加进去,第三,执行事务。

  

你会发现这不是一个笑话,这是认真的。

  

<强>试图找到一个入口

  

当你面对一个完全不熟悉的事物时,一定要想办法找到一个突破口,然后逐步深入,那春天事物的突破口在哪里呢?很明显在@EnableTransactionManagement注解里,因为是它启用了事物功能。

  

请看下图:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

发现注解还引入了一个类TransactionManagementConfigurationSelector。

  

再来看这个类,如下图:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

发现如果采用代理的方式时,又引入了一个类ProxyTransactionManagementConfiguration。

  

接着看这个类(重点来了),如下图:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

发现这个类往容器中注册了3个bean,第一个是BeanFactoryTransactionAttributeSourceAdvisor。它以顾问结尾说明它是Spring AOP范畴里的东西。

  

在AOP里,顾问=切入点+建议,切入点是切入点,表示要拦截的方法,建议是增强,表示要加进去的事物功能。

  

再看看另外两个注册的bean,就是和这两个相关的。其中TransactionInterceptor就是一个建议,因为它实现了建议接口,包含了把事物加进去的逻辑。

  

TransactionAttributeSource虽然不是一个切入点,但是它被切入点所用,用于检测一个类的方法上是否有@ transactional注解,来确定该方法是否需要事物增强。

  

从下图中也可以看出这一点:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

可以看到这个bean通过下面组的方法被设置进去,然后又用在了切入点的类里了。

  

整体来看,此部分的结构和功能划分还是非常清晰的。下面来逐一研究。

  

<强> AOP切点

  

TransactionAttributeSourcePointcut类以切入点结尾,说明它是一个切入点,就是标识要被拦截的方法,类名的前缀部分表明了这个切入点的实现原理。

  

看下这个前缀是TransactionAttributeSource,它以源结尾,说明它是一个源(即源泉,有向外提供东西的意思)。它的前缀是TransactionAttribute,即事务属性。

  

由此可见,这个源可以向外提供事务属性,其实就是判断一个类的方法上是否标有@ transactional注解,如果有的话还可以获取这个注解的属性(即事务属性)。

  

整体来说就是,切入点拦截住了方法,然后使用这个“源”去方法和类上获取事务属性,如果能获取到,说明此方法需要参与事务,则进行事务增强,反之则不增强。

  

下面这张图可以证明我们的想法:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

可以看出匹配方法的两个参数就是一个方法(方法)和一个类(Class<& # 63;祝辞)。最后从方法和类上获取事务属性,再进行是否为空判断。

  

现在这个“源”还是个黑盒子,下面来揭开它的面纱。它的实现类是AnnotationTransactionAttributeSource,以注释开的头,说明是基于注解实现的。

  

下面图是它的源码的一部分:

  

【面试】春天事务面试考点吐血整理(建议珍藏)

  

第一个方法从类上找事务属性,第二个方法从方法上找事务属性,它俩都调用了第三个方法来实现。

  

PS:我们都知道,方法上的注解优先级高于类上的,是因为找注解时先找方法上的,找不到时再去类上找,所以方法上的优先级高。此部分代码逻辑在父类里写着呢,这里不再展示了。

  

第三个方法使用多个事务注解解析器(TransactionAnnotationParser)去解析注解,为啥是多个解析器呢?因为事务注解不仅春提供了,Java后来也提供了,就是javax.transaction.Transactional。

【面试】春天事务面试考点吐血整理(建议珍藏)