@Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable)")
org.mengyun.tcctransaction.spring.ConfigurableTransactionAspect
顺序 Ordered.HIGHEST_PRECEDENCE;
org.mengyun.tcctransaction.interceptor.ResourceCoordinatorAspect
顺序Ordered.HIGHEST_PRECEDENCE + 1;
ConfigurableTransactionAspect负责管理事务,包括开启事务;
ResourceCoordinatorAspect负责协调事务参与者,包括创建参与者列表等。
public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
CompensableMethodContext compensableMethodContext = new CompensableMethodContext(pjp);
// 判断当前线程是否已经创建事务
boolean isTransactionActive = transactionManager.isTransactionActive();
// 校验事务传播属性为mandatory时,当前必须要有事务,否则报错
if (!TransactionUtils.isLegalTransactionContext(isTransactionActive, compensableMethodContext)) {
throw new SystemException("no active compensable transaction while propagation is mandatory for method " + compensableMethodContext.getMethod().getName());
}
// 注释在下面
switch (compensableMethodContext.getMethodRole(isTransactionActive)) {
case ROOT:
return rootMethodProceed(compensableMethodContext);
case PROVIDER:
return providerMethodProceed(compensableMethodContext);
default:
return pjp.proceed();
}
}
/**
* getMethodRole方法中的逻辑是:
* 1. 如果需要分布式事务,当前线程还没有创建事务,事务上下文为空,那么这就是一个根事务ROOT;
* 2. 如果需要分布式事务,当前线程还没有创建事务,但是事务上下文不为空,这种情况事务上下文是作为参 * 数传过来的,此时就是个参与事务的分支服务的方法,类型为PROVIDER;
* 3. 否则的话就是个普通方法,类型为NORMAL
*/
public MethodRole getMethodRole(boolean isTransactionActive) {
if ((propagation.equals(Propagation.REQUIRED) && !isTransactionActive && transactionContext == null) ||
propagation.equals(Propagation.REQUIRES_NEW)) {
return MethodRole.ROOT;
} else if ((propagation.equals(Propagation.REQUIRED) || propagation.equals(Propagation.MANDATORY)) && !isTransactionActive && transactionContext != null) {
return MethodRole.PROVIDER;
} else {
return MethodRole.NORMAL;
}
}
private Object rootMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {
Object returnValue = null;
Transaction transaction = null;
// 获取注解中异步确认和异步取消的配置
boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();
// 设置哪些异常情况下,不直接执行回滚方法,比如超时异常等,此时服务提供方不一定失败了,可能在调用超过之后还会正确的返回
Set<Class<? extends Exception>> allDelayCancelExceptions = new HashSet<Class<? extends Exception>>();
allDelayCancelExceptions.addAll(this.delayCancelExceptions);
allDelayCancelExceptions.addAll(Arrays.asList(compensableMethodContext.getAnnotation().delayCancelExceptions()));
try {
// 开启一个事务
transaction = transactionManager.begin(compensableMethodContext.getUniqueIdentity());
try {
// 真正执行业务方法
returnValue = compensableMethodContext.proceed();
} catch (Throwable tryingException) {
// 如果执行业务try方法抛出了异常,并且不是延迟回复你的异常的时候,直接回滚
if (!isDelayCancelException(tryingException, allDelayCancelExceptions)) {
logger.warn(String.format("compensable transaction trying failed. transaction content:%s", JSON.toJSONString(transaction)), tryingException);
transactionManager.rollback(asyncCancel);
}
throw tryingException;
}
// 如果try方法没有异常,提交事务
transactionManager.commit(asyncConfirm);
} finally {
// try方法执行结束后清理资源
transactionManager.cleanAfterCompletion(transaction);
}
return returnValue;
}
public Transaction begin(Object uniqueIdentify) {
/** 创建一个事务,如果没有通过UniqueIdentity注解设置事务唯一id,通过uuid生成一个,事务类型是
* TransactionType.ROOT,事务状态是TRYING
*/
Transaction transaction = new Transaction(uniqueIdentify,TransactionType.ROOT);
// 把事务记录到TCC库的表里,存了哪些字段等具体可以到JdbcTransactionRepository里看
transactionRepository.create(transaction);
// 事务记录到当前线程的事务队列汇总
registerTransaction(transaction);
return transaction;
}
/**
* 逐个调用所有事务参与者的确认方法
*/
public void commit() {
for (Participant participant : participants) {
participant.commit();
}
}
public void commit() {
Terminator.invoke(new TransactionContext(xid, TransactionStatus.CONFIRMING.getId()), confirmInvocationContext, transactionContextEditorClass);
}
/**
* 逐个调用所有事务参与者的取消方法
*/
public void rollback() {
for (Participant participant : participants) {
participant.rollback();
}
}
public void rollback() {
Terminator.invoke(new TransactionContext(xid, TransactionStatus.CANCELLING.getId()), cancelInvocationContext, transactionContextEditorClass);
}
public Transaction begin(Object uniqueIdentify) {
/** 创建一个事务,如果没有通过UniqueIdentity注解设置事务唯一id,通过uuid生成一个,事务类型是
* TransactionType.ROOT,事务状态是TRYING
*/
Transaction transaction = new Transaction(uniqueIdentify,TransactionType.ROOT);
// 把事务记录到TCC库的表里,存了哪些字段等具体可以到JdbcTransactionRepository里看
transactionRepository.create(transaction);
// 事务记录到当前线程的事务队列汇总
registerTransaction(transaction);
return transaction;
}
private Object providerMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {
Transaction transaction = null;
boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();
try {
switch (TransactionStatus.valueOf(compensableMethodContext.getTransactionContext().getStatus())) {
case TRYING:
// 如果事务状态是TRYING,创建分支事务,事务id是事务上下文中获取到的,类型是BRANCH,状态是TRYING,然后执行业务方法
transaction = transactionManager.propagationNewBegin(compensableMethodContext.getTransactionContext());
return compensableMethodContext.proceed();
case CONFIRMING:
try {
// 如果事务状态是CONFIRMING,根据事务id更新TCC库中事务的状态为CONFIRMING,然后提交事务
transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());
transactionManager.commit(asyncConfirm);
} catch (NoExistedTransactionException excepton) {
//the transaction has been commit,ignore it.
}
break;
case CANCELLING:
try {
// 如果事务状态是CANCELLING,根据事务id更新TCC库中事务的状态为CANCELLING,然后回滚事务
transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());
transactionManager.rollback(asyncCancel);
} catch (NoExistedTransactionException exception) {
//the transaction has been rollback,ignore it.
}
break;
}
} finally {
transactionManager.cleanAfterCompletion(transaction);
}
// 能走到这里上面case里的流程都失败了,返回默认值
Method method = compensableMethodContext.getMethod();
return ReflectionUtils.getNullValue(method.getReturnType());
}
public Object interceptTransactionContextMethod(ProceedingJoinPoint pjp) throws Throwable {
// 获取当前线程事务
Transaction transaction = transactionManager.getCurrentTransaction();
// 如果事务不为空(已经在事务管理切面创建过了)
if (transaction != null) {
// 事务是trying阶段的时候,加入到事务参与者列表,其他阶段直接执行
switch (transaction.getStatus()) {
case TRYING:
enlistParticipant(pjp);
break;
case CONFIRMING:
break;
case CANCELLING:
break;
}
}
return pjp.proceed(pjp.getArgs());
}
private void enlistParticipant(ProceedingJoinPoint pjp) throws IllegalAccessException, InstantiationException {
// 获取事务注解的方法
Method method = CompensableMethodUtils.getCompensableMethod(pjp);
if (method == null) {
throw new RuntimeException(String.format("join point not found method, point is : %s", pjp.getSignature().getName()));
}
// 从方法的注解里面提取出来确认方法和取消方法
Compensable compensable = method.getAnnotation(Compensable.class);
String confirmMethodName = compensable.confirmMethod();
String cancelMethodName = compensable.cancelMethod();
// 获取当前事务和事务id
Transaction transaction = transactionManager.getCurrentTransaction();
TransactionXid xid = new TransactionXid(transaction.getXid().getGlobalTransactionId());
/**
* 遍历try方法所有参数,如果没有TransactionContext类型的参数,则
*
*/
if (FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs()) == null) {
FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().set(new TransactionContext(xid, TransactionStatus.TRYING.getId()), pjp.getTarget(), ((MethodSignature) pjp.getSignature()).getMethod(), pjp.getArgs());
}
// 获取事务注解拦截的类
Class targetClass = ReflectionUtils.getDeclaringType(pjp.getTarget().getClass(), method.getName(), method.getParameterTypes());
// 把类、确认方法(取消方法)、方法参数类型、参数值构造成方法调用封装类
InvocationContext confirmInvocation = new InvocationContext(targetClass,
confirmMethodName,
method.getParameterTypes(), pjp.getArgs());
InvocationContext cancelInvocation = new InvocationContext(targetClass,
cancelMethodName,
method.getParameterTypes(), pjp.getArgs());
// 把事务id、调用方法封装、取消方法封装、事务上下文组装成一个参与者
Participant participant =
new Participant(
xid,
confirmInvocation,
cancelInvocation,
compensable.transactionContextEditor());
// 把事务参与者加入到事务管理器的参与者列表
transactionManager.enlistParticipant(participant);
}