Java Spring @Transactional

@Transactional注解简介

@Transactional是spring中声明式事务管理的注解配置方式,相信这个注解的作用大家都很清楚。@Transactional注解可以把事务开启、提交或者回滚的操作,通过aop的方式进行管理。
通过@Transactional注解就能让Spring管理事务,免去了重复的事务管理逻辑,减少对业务代码的侵入,使开发人员能够专注于业务层面开发。
2021-05-31-17-53-01-028737.png
实现@Transactional原理是基于Spring aop,aop又是动态代理模式的实现,通过对源码的阅读,总结出下面的步骤来了解实际中,在Spring 是如何利用aop来实现@Transactional的功能的。

Spring中声明式事务实现原理猜想

首先,对于Spring中aop实现原理有了解的话,应该知道想要对一个方法进行代理的话,肯定需要定义切点。在@Transactional的实现中,同样如此,Spring定义了以 @Transactional 注解为植入点的切点,这样才能知道@Transactional注解标注的方法需要被代理。
有了切面定义之后,在Spring的bean的初始化过程中,就需要对实例化的bean进行代理,并且生成代理对象。
生成代理对象的代理逻辑中,进行方法调用时,需要先获取切面逻辑,@Transactional注解的切面逻辑类似于@Around,在Spring中是实现一种类似代理逻辑。
2021-05-31-17-53-01-149436.png

@Transactional作用

根据上面的原理猜想,下面简单介绍每个步骤的源码以进行验证。
首先是@Transactional,作用是定义代理植入点。代理对象创建的通过BeanPostProcessor的实现类AnnotationAwareAspectJAutoProxyCreatorpostProcessAfterInstantiation方法来实现个,如果需要进行代理,那么在这个方法就会返回一个代理对象给容器,同时判断植入点也是在这个方法中。
那么下面开始分析,在配置好注解驱动方式的事务管理之后,Spring会在ioc容器创建一个BeanFactoryTransactionAttributeSourceAdvisor实例,这个实例可以看作是一个切点,在判断一个bean在初始化过程中是否需要创建代理对象,都需要验证一次BeanFactoryTransactionAttributeSourceAdvisor是否是适用这个bean的切点。如果是,就需要创建代理对象,并且把BeanFactoryTransactionAttributeSourceAdvisor实例注入到代理对象中。
AopUtils#findAdvisorsThatCanApply中判断切面是否适用当前bean,可以在这个地方断点分析调用堆栈,AopUtils#findAdvisorsThatCanApply一致调用,最终通过以下代码判断是否适用切点。

  • AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class<?> targetClass) 这里可以根据参数打上条件断点进行调试分析调用栈,targetClass就是目标class …一系列调用
  • 最终SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

    1. @Override
    2. public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    3. //这里就是分析Method是否被@Transactional注解标注,有的话,不用说BeanFactoryTransactionAttributeSourceAdvisor适配当前bean,进行代理,并且注入切点
    4. //BeanFactoryTransactionAttributeSourceAdvisor
    5. AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
    6. if (attributes != null) {
    7. return parseTransactionAnnotation(attributes);
    8. }
    9. else {
    10. return null;
    11. }
    12. }

    上面就是判断是否需要根据@Transactional进行代理对象创建的判断过程。@Transactional的作用一个就是标识方法需要被代理,一个就是携带事务管理需要的一些属性信息。

    动态代理逻辑实现

    【aop实现原理分析】中知道,aop最终的代理对象的代理方法是

  • DynamicAdvisedInterceptor#intercept

所以可以在这个方法断点分析代理逻辑。

  1. @Override
  2. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  3. Object oldProxy = null;
  4. boolean setProxyContext = false;
  5. Class<?> targetClass = null;
  6. Object target = null;
  7. try {
  8. if (this.advised.exposeProxy) {
  9. // Make invocation available if necessary.
  10. oldProxy = AopContext.setCurrentProxy(proxy);
  11. setProxyContext = true;
  12. }
  13. // May be null. Get as late as possible to minimize the time we
  14. // "own" the target, in case it comes from a pool...
  15. target = getTarget();
  16. if (target != null) {
  17. targetClass = target.getClass();
  18. }
  19. //follow
  20. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  21. Object retVal;
  22. // Check whether we only have one InvokerInterceptor: that is,
  23. // no real advice, but just reflective invocation of the target.
  24. if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
  25. // We can skip creating a MethodInvocation: just invoke the target directly.
  26. // Note that the final invoker must be an InvokerInterceptor, so we know
  27. // it does nothing but a reflective operation on the target, and no hot
  28. // swapping or fancy proxying.
  29. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  30. retVal = methodProxy.invoke(target, argsToUse);
  31. }
  32. else {
  33. // We need to create a method invocation...
  34. retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
  35. }
  36. retVal = processReturnType(proxy, target, method, retVal);
  37. return retVal;
  38. }
  39. finally {
  40. if (target != null) {
  41. releaseTarget(target);
  42. }
  43. if (setProxyContext) {
  44. // Restore old proxy.
  45. AopContext.setCurrentProxy(oldProxy);
  46. }
  47. }
  48. }

通过分析 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)返回的是TransactionInterceptor,利用TransactionInterceptor是如何实现代理逻辑调用的?
跟踪new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
发现最终是调用TransactionInterceptor#invoke方法,并且把CglibMethodInvocation注入到invoke方法中,从上面可以看到CglibMethodInvocation是包装了目标对象的方法调用的所有必须信息,因此,在TransactionInterceptor#invoke里面也是可以调用目标方法的,并且还可以实现类似@Around的逻辑,在目标方法调用前后继续注入一些其他逻辑,比如事务管理逻辑。

TransactionInterceptor–最终事务管理者

下面看代码。

  • TransactionInterceptor#invoke

    1. @Override
    2. public Object invoke(final MethodInvocation invocation) throws Throwable {
    3. // Work out the target class: may be {@code null}.
    4. // The TransactionAttributeSource should be passed the target class
    5. // as well as the method, which may be from an interface.
    6. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    7. // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    8. return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
    9. @Override
    10. public Object proceedWithInvocation() throws Throwable {
    11. return invocation.proceed();
    12. }
    13. });
    14. }

    继续跟踪invokeWithinTransaction,下面的代码中其实就可以看出一些逻辑端倪,就是猜想的实现方式,事务管理。

    1. protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
    2. throws Throwable {
    3. // If the transaction attribute is null, the method is non-transactional.
    4. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    5. final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    6. final String joinpointIdentification = methodIdentification(method, targetClass);
    7. if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    8. // Standard transaction demarcation with getTransaction and commit/rollback calls.
    9. //开启事务
    10. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    11. Object retVal = null;
    12. try {
    13. // This is an around advice: Invoke the next interceptor in the chain.
    14. // This will normally result in a target object being invoked.
    15. //方法调用
    16. retVal = invocation.proceedWithInvocation();
    17. }
    18. catch (Throwable ex) {
    19. // target invocation exception
    20. //回滚事务
    21. completeTransactionAfterThrowing(txInfo, ex);
    22. throw ex;
    23. }
    24. finally {
    25. cleanupTransactionInfo(txInfo);
    26. }
    27. //提交事务
    28. commitTransactionAfterReturning(txInfo);
    29. return retVal;
    30. }
    31. else {
    32. // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
    33. try {
    34. Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
    35. new TransactionCallback<Object>() {
    36. @Override
    37. public Object doInTransaction(TransactionStatus status) {
    38. TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
    39. try {
    40. return invocation.proceedWithInvocation();
    41. }
    42. catch (Throwable ex) {
    43. if (txAttr.rollbackOn(ex)) {
    44. // A RuntimeException: will lead to a rollback.
    45. if (ex instanceof RuntimeException) {
    46. throw (RuntimeException) ex;
    47. }
    48. else {
    49. throw new ThrowableHolderException(ex);
    50. }
    51. }
    52. else {
    53. // A normal return value: will lead to a commit.
    54. return new ThrowableHolder(ex);
    55. }
    56. }
    57. finally {
    58. cleanupTransactionInfo(txInfo);
    59. }
    60. }
    61. });
    62. // Check result: It might indicate a Throwable to rethrow.
    63. if (result instanceof ThrowableHolder) {
    64. throw ((ThrowableHolder) result).getThrowable();
    65. }
    66. else {
    67. return result;
    68. }
    69. }
    70. catch (ThrowableHolderException ex) {
    71. throw ex.getCause();
    72. }
    73. }
    74. }

    总结

    最终可以总结一下整个流程,跟开始的猜想对照。
    2021-05-31-17-53-01-277152.png
    分析源码后对照
    2021-05-31-17-53-01-446663.png