事务是一种all or nothing的执行策略,常见数据库,这种策略遵从ACID原则,可以很好的保证业务的执行,spring事务底层可以使用tx命名空间实现,也可以通过Transactional注解的方式来实现,本文就讲下spring transactional注解底层的工作原理,要了解这个工作原理,首先要了解cglib的工作原理,这个可以参考文章:https://blog.csdn.net/john1337/article/details/88762825
了解了cglib的基本工作原理后,spring transactional底层工作原理就很容易理解了,笔者就把这个运作原理涉及到的几个重要的相关类在这里列举出来,感兴趣的进行代码跟踪即可了解:
DefaultAdvisorAutoProxyCreator 这是BeanPostProcessor,重要的其基类AbstractAdvisorAutoProxyCreator的postProcessAfterInitialization方法,这个方法内部生成了对应service的代理类,基本代理类代码类似下面:
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private NoOp CGLIB$CALLBACK_2;
private Dispatcher CGLIB$CALLBACK_3;
private Dispatcher CGLIB$CALLBACK_4;
private MethodInterceptor CGLIB$CALLBACK_5;
private MethodInterceptor CGLIB$CALLBACK_6;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$insert$0$Method;
private static final MethodProxy CGLIB$insert$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$selectByPrimaryKey$1$Method;
private static final MethodProxy CGLIB$selectByPrimaryKey$1$Proxy;
private static final Method CGLIB$updateByPrimaryKeySelective$2$Method;
private static final MethodProxy CGLIB$updateByPrimaryKeySelective$2$Proxy;
private static final Method CGLIB$updateByPrimaryKey$3$Method;
private static final MethodProxy CGLIB$updateByPrimaryKey$3$Proxy;
private static final Method CGLIB$insertSelective$4$Method;
private static final MethodProxy CGLIB$insertSelective$4$Proxy;
private static final Method CGLIB$deleteByPrimaryKey$5$Method;
private static final MethodProxy CGLIB$deleteByPrimaryKey$5$Proxy;
private static final Method CGLIB$equals$6$Method;
private static final MethodProxy CGLIB$equals$6$Proxy;
private static final Method CGLIB$toString$7$Method;
private static final MethodProxy CGLIB$toString$7$Proxy;
private static final Method CGLIB$hashCode$8$Method;
private static final MethodProxy CGLIB$hashCode$8$Proxy;
private static final Method CGLIB$clone$9$Method;
private static final MethodProxy CGLIB$clone$9$Proxy;
static void CGLIB$STATICHOOK249() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("hello.service.bank.impl.SubBankServiceImpl$$EnhancerBySpringCGLIB$$8fea4d01");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$6$Method = var10000[0];
CGLIB$equals$6$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$6");
CGLIB$toString$7$Method = var10000[1];
CGLIB$toString$7$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$7");
CGLIB$hashCode$8$Method = var10000[2];
CGLIB$hashCode$8$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$8");
CGLIB$clone$9$Method = var10000[3];
CGLIB$clone$9$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$9");
var10000 = ReflectUtils.findMethods(new String[]{"insert", "(Lhello/entity/bank/SubBank;)I", "selectByPrimaryKey", "(Ljava/lang/String;)Lhello/entity/bank/SubBank;", "updateByPrimaryKeySelective", "(Lhello/entity/bank/SubBank;)I", "updateByPrimaryKey", "(Lhello/entity/bank/SubBank;)I", "insertSelective", "(Lhello/entity/bank/SubBank;)I", "deleteByPrimaryKey", "(Ljava/lang/String;)I"}, (var1 = Class.forName("hello.service.bank.impl.SubBankServiceImpl")).getDeclaredMethods());
CGLIB$insert$0$Method = var10000[0];
CGLIB$insert$0$Proxy = MethodProxy.create(var1, var0, "(Lhello/entity/bank/SubBank;)I", "insert", "CGLIB$insert$0");
CGLIB$selectByPrimaryKey$1$Method = var10000[1];
CGLIB$selectByPrimaryKey$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Lhello/entity/bank/SubBank;", "selectByPrimaryKey", "CGLIB$selectByPrimaryKey$1");
CGLIB$updateByPrimaryKeySelective$2$Method = var10000[2];
CGLIB$updateByPrimaryKeySelective$2$Proxy = MethodProxy.create(var1, var0, "(Lhello/entity/bank/SubBank;)I", "updateByPrimaryKeySelective", "CGLIB$updateByPrimaryKeySelective$2");
CGLIB$updateByPrimaryKey$3$Method = var10000[3];
CGLIB$updateByPrimaryKey$3$Proxy = MethodProxy.create(var1, var0, "(Lhello/entity/bank/SubBank;)I", "updateByPrimaryKey", "CGLIB$updateByPrimaryKey$3");
CGLIB$insertSelective$4$Method = var10000[4];
CGLIB$insertSelective$4$Proxy = MethodProxy.create(var1, var0, "(Lhello/entity/bank/SubBank;)I", "insertSelective", "CGLIB$insertSelective$4");
CGLIB$deleteByPrimaryKey$5$Method = var10000[5];
CGLIB$deleteByPrimaryKey$5$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)I", "deleteByPrimaryKey", "CGLIB$deleteByPrimaryKey$5");
}
final int CGLIB$insert$0(SubBank var1) {
return super.insert(var1);
}
public final int insert(SubBank var1) {
try {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var4 = var10000.intercept(this, CGLIB$insert$0$Method, new Object[]{var1}, CGLIB$insert$0$Proxy);
return var4 == null ? 0 : ((Number)var4).intValue();
} else {
return super.insert(var1);
}
} catch (Error | RuntimeException var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
这个就是cglib产生的代理类
CglibAopProxy 这个类getProxy创建了对应的cglib代理
DynamicAdvisedInterceptor 这个类实现了MethodInteceptor接口,每次Service调用接口时首先进入的就是DynamicAdvisedInterceptor这个类的intercept方法,该方法内部会判断每个要执行的方法是否有对应的advice,被Transactional注解的方法对应的默认advice就是TransactionInteceptor
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();
}
});
}