public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    Method method = methodInvocation.getMethod();

    Class<?> targetClass = null;

    Object thisObject = methodInvocation.getThis();

    if (thisObject != null) {
      targetClass = thisObject.getClass();
    }

    TransactionAttributeSource transactionAttributeSource = getTransactionAttributeSource();

    TransactionAttribute transactionAttribute =
        transactionAttributeSource.getTransactionAttribute(method, targetClass);

    Class<?> declaringClass = method.getDeclaringClass();

    String joinPointIdentification =
        declaringClass.getName().concat(StringPool.PERIOD).concat(method.getName());

    TransactionInfo transactionInfo =
        createTransactionIfNecessary(
            getTransactionManager(), transactionAttribute, joinPointIdentification);

    Object returnValue = null;

    try {
      returnValue = methodInvocation.proceed();
    } catch (Throwable throwable) {
      completeTransactionAfterThrowing(transactionInfo, throwable);

      throw throwable;
    } finally {
      cleanupTransactionInfo(transactionInfo);
    }

    commitTransactionAfterReturning(transactionInfo);

    return returnValue;
  }
 /**
  * checks method (and as a fallback the class) for the Spring {@link Transactional} annotation.
  *
  * @param mi Non-null method invocation.
  * @return true if the {@link Transactional} annotation lists this method as read-only, or if no
  *     annotation is found.
  */
 boolean checkReadOnly(MethodInvocation mi) {
   TransactionAttribute ta =
       txSource.getTransactionAttribute(mi.getMethod(), mi.getThis().getClass());
   return ta == null ? true : ta.isReadOnly();
 }