关于java:面试官Transactional-注解是如何实现的

38次阅读

共计 7036 个字符,预计需要花费 18 分钟才能阅读完成。

@Transactional 注解简介

@Transactional是 spring 中申明式事务管理的注解配置形式,置信这个注解的作用大家都很分明。@Transactional注解能够帮忙咱们把事务开启、提交或者回滚的操作,通过 aop 的形式进行治理。

通过 @Transactional 注解就能让 spring 为咱们治理事务,免去了反复的事务管理逻辑,缩小对业务代码的侵入,使咱们开发人员可能专一于业务层面开发。

咱们晓得实现 @Transactional 原理是基于 spring aop,aop 又是动静代理模式的实现,通过对源码的浏览,总结出上面的步骤来理解理论中,在 spring 是如何利用 aop 来实现 @Transactional 的性能的。

spring 中申明式事务实现原理猜测

首先,对于 spring 中 aop 实现原理有理解的话,应该晓得想要对一个办法进行代理的话,必定须要定义切点。在 @Transactional 的实现中,同样如此,spring 为咱们定义了以 @Transactional 注解为植入点的切点,这样能力晓得 @Transactional 注解标注的办法须要被代理。

有了切面定义之后,在 spring 的 bean 的初始化过程中,就须要对实例化的 bean 进行代理,并且生成代理对象。

生成代理对象的代理逻辑中,进行办法调用时,须要先获取切面逻辑,@Transactional 注解的切面逻辑相似于 @Around,在 spring 中是实现一种相似代理逻辑。

@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)
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    // 这里就是剖析 Method 是否被 @Transactional 注解标注,有的话,不用说 BeanFactoryTransactionAttributeSourceAdvisor 适配以后 bean,进行代理,并且注入切点
    //BeanFactoryTransactionAttributeSourceAdvisor
   AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
   if (attributes != null) {return parseTransactionAnnotation(attributes);
   }
   else {return null;}
}

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

举荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks…

动静代理逻辑实现

【aop 实现原理剖析】中晓得,aop 最终的代理对象的代理办法是

  • DynamicAdvisedInterceptor#intercept

所以咱们能够在这个办法断点剖析代理逻辑。

@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
   Class<?> targetClass = null;
   Object target = null;
   try {if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      // May be null. Get as late as possible to minimize the time we
      // "own" the target, in case it comes from a pool...
      target = getTarget();
      if (target != null) {targetClass = target.getClass();
      }
       //follow
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      // Check whether we only have one InvokerInterceptor: that is,
      // no real advice, but just reflective invocation of the target.
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         // We can skip creating a MethodInvocation: just invoke the target directly.
         // Note that the final invoker must be an InvokerInterceptor, so we know
         // it does nothing but a reflective operation on the target, and no hot
         // swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
         // We need to create a method invocation...
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {if (target != null) {releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

通过剖析 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
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.
 // The TransactionAttributeSource should be passed the target class
 // as well as the method, which may be from an interface.
 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

 // Adapt to TransactionAspectSupport's invokeWithinTransaction...
 return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
  @Override
  public Object proceedWithInvocation() throws Throwable {return invocation.proceed();
  }
 });
}

持续跟踪 invokeWithinTransaction,上面的代码中其实就能够看出一些逻辑端倪,就是咱们猜测的实现形式,事务管理。

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
      throws Throwable {

   // If the transaction attribute is null, the method is non-transactional.
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   final String joinpointIdentification = methodIdentification(method, targetClass);

   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
       // 开启事务
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      Object retVal = null;
      try {
         // This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
          // 办法调用
         retVal = invocation.proceedWithInvocation();}
      catch (Throwable ex) {
         // target invocation exception
     // 回滚事务
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {cleanupTransactionInfo(txInfo);
      }
       // 提交事务
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }

   else {
      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
      try {Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
               new TransactionCallback<Object>() {
                  @Override
                  public Object doInTransaction(TransactionStatus status) {TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                     try {return invocation.proceedWithInvocation();
                     }
                     catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {
                           // A RuntimeException: will lead to a rollback.
                           if (ex instanceof RuntimeException) {throw (RuntimeException) ex;
                           }
                           else {throw new ThrowableHolderException(ex);
                           }
                        }
                        else {
                           // A normal return value: will lead to a commit.
                           return new ThrowableHolder(ex);
                        }
                     }
                     finally {cleanupTransactionInfo(txInfo);
                     }
                  }
               });

         // Check result: It might indicate a Throwable to rethrow.
         if (result instanceof ThrowableHolder) {throw ((ThrowableHolder) result).getThrowable();}
         else {return result;}
      }
      catch (ThrowableHolderException ex) {throw ex.getCause();
      }
   }
}

总结

最终能够总结一下整个流程,跟开始的猜测对照。

剖析源码后对照

原文链接:https://blog.csdn.net/qq_2059…

版权申明:本文为 CSDN 博主「一撸向北」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 别在再满屏的 if/ else 了,试试策略模式,真香!!

3. 卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0